diff --git a/.lock b/.lock new file mode 100755 index 000000000..e69de29bb diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt new file mode 100644 index 000000000..16d79032f --- /dev/null +++ b/COPYRIGHT.txt @@ -0,0 +1,46 @@ +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff, FiraSans-Medium.woff): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff, + SourceCodePro-Semibold.ttf.woff, SourceCodePro-It.ttf.woff): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff, SourceSerif4-Bold.ttf.woff, + SourceSerif4-It.ttf.woff): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/FiraSans-LICENSE.txt b/FiraSans-LICENSE.txt new file mode 100644 index 000000000..d444ea92b --- /dev/null +++ b/FiraSans-LICENSE.txt @@ -0,0 +1,94 @@ +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/FiraSans-Medium.woff b/FiraSans-Medium.woff new file mode 100644 index 000000000..7d742c5fb Binary files /dev/null and b/FiraSans-Medium.woff differ diff --git a/FiraSans-Medium.woff2 b/FiraSans-Medium.woff2 new file mode 100644 index 000000000..7a1e5fc54 Binary files /dev/null and b/FiraSans-Medium.woff2 differ diff --git a/FiraSans-Regular.woff b/FiraSans-Regular.woff new file mode 100644 index 000000000..d8e0363f4 Binary files /dev/null and b/FiraSans-Regular.woff differ diff --git a/FiraSans-Regular.woff2 b/FiraSans-Regular.woff2 new file mode 100644 index 000000000..e766e06cc Binary files /dev/null and b/FiraSans-Regular.woff2 differ diff --git a/LICENSE-APACHE.txt b/LICENSE-APACHE.txt new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/LICENSE-APACHE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/LICENSE-MIT.txt b/LICENSE-MIT.txt new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/LICENSE-MIT.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/SourceCodePro-It.ttf.woff b/SourceCodePro-It.ttf.woff new file mode 100644 index 000000000..8d68f2feb Binary files /dev/null and b/SourceCodePro-It.ttf.woff differ diff --git a/SourceCodePro-LICENSE.txt b/SourceCodePro-LICENSE.txt new file mode 100644 index 000000000..07542572e --- /dev/null +++ b/SourceCodePro-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/SourceCodePro-Regular.ttf.woff b/SourceCodePro-Regular.ttf.woff new file mode 100644 index 000000000..7be076e1f Binary files /dev/null and b/SourceCodePro-Regular.ttf.woff differ diff --git a/SourceCodePro-Semibold.ttf.woff b/SourceCodePro-Semibold.ttf.woff new file mode 100644 index 000000000..61bc67b80 Binary files /dev/null and b/SourceCodePro-Semibold.ttf.woff differ diff --git a/SourceSerif4-Bold.ttf.woff b/SourceSerif4-Bold.ttf.woff new file mode 100644 index 000000000..8ad41888e Binary files /dev/null and b/SourceSerif4-Bold.ttf.woff differ diff --git a/SourceSerif4-It.ttf.woff b/SourceSerif4-It.ttf.woff new file mode 100644 index 000000000..2a34b5c42 Binary files /dev/null and b/SourceSerif4-It.ttf.woff differ diff --git a/SourceSerif4-LICENSE.md b/SourceSerif4-LICENSE.md new file mode 100644 index 000000000..68ea18924 --- /dev/null +++ b/SourceSerif4-LICENSE.md @@ -0,0 +1,93 @@ +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/SourceSerif4-Regular.ttf.woff b/SourceSerif4-Regular.ttf.woff new file mode 100644 index 000000000..45a5521ab Binary files /dev/null and b/SourceSerif4-Regular.ttf.woff differ diff --git a/arch/all.html b/arch/all.html new file mode 100644 index 000000000..5b01597e8 --- /dev/null +++ b/arch/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/arch/fn.main.html b/arch/fn.main.html new file mode 100644 index 000000000..ae4da4951 --- /dev/null +++ b/arch/fn.main.html @@ -0,0 +1,3 @@ +main in arch - Rust + +

Function arch::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/arch/index.html b/arch/index.html new file mode 100644 index 000000000..55f09ad32 --- /dev/null +++ b/arch/index.html @@ -0,0 +1,4 @@ +arch - Rust + +

Crate arch[][src]

Functions

+
main
\ No newline at end of file diff --git a/arch/sidebar-items.js b/arch/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/arch/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/ayu.css b/ayu.css new file mode 100644 index 000000000..94ffc1cb9 --- /dev/null +++ b/ayu.css @@ -0,0 +1 @@ + body{background-color:#0f1419;color:#c5c5c5;}h1,h2,h3,h4{color:white;}h1.fqn{border-bottom-color:#5c6773;}h1.fqn a{color:#fff;}h2,h3,h4{border-bottom-color:#5c6773;}h4{border:none;}.in-band{background-color:#0f1419;}.invisible{background:rgba(0,0,0,0);}code{color:#ffb454;}h3>code,h4>code,h5>code{color:#e6e1cf;}pre>code{color:#e6e1cf;}span code{color:#e6e1cf;}.docblock a>code{color:#39AFD7 !important;}.docblock code,.docblock-short code{background-color:#191f26;}pre,.rustdoc.source .example-wrap{color:#e6e1cf;background-color:#191f26;}.sidebar{background-color:#14191f;}.logo-container.rust-logo>img{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);}*{scrollbar-color:#5c6773 transparent;}.sidebar{scrollbar-color:#5c6773 transparent;}::-webkit-scrollbar-track{background-color:transparent;}::-webkit-scrollbar-thumb{background-color:#5c6773;}.sidebar::-webkit-scrollbar-track{background-color:transparent;}.sidebar::-webkit-scrollbar-thumb{background-color:#5c6773;}.sidebar .current{background-color:transparent;color:#ffb44c;}.source .sidebar{background-color:#0f1419;}.sidebar .location{border-color:#000;background-color:#0f1419;color:#fff;}.sidebar-elems .location{color:#ff7733;}.sidebar-elems .location a{color:#fff;}.sidebar .version{border-bottom-color:#424c57;}.sidebar-title{border-top-color:#5c6773;border-bottom-color:#5c6773;}.block a:hover{background:transparent;color:#ffb44c;}.line-numbers span{color:#5c6773;}.line-numbers .line-highlighted{color:#708090;background-color:rgba(255,236,164,0.06);padding-right:4px;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#5c6773;}.docblock table,.docblock table td,.docblock table th{border-color:#5c6773;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#c5c5c5;}.search-results a:hover{background-color:#777;}.search-results a:focus{color:#000 !important;background-color:#c6afb3;}.search-results a{color:#0096cf;}.search-results a span.desc{color:#c5c5c5;}.content .item-info::before{color:#ccc;}.content span.foreigntype,.content a.foreigntype{color:#ef57ff;}.content span.union,.content a.union{color:#98a01c;}.content span.constant,.content a.constant,.content span.static,.content a.static{color:#6380a0;}.content span.primitive,.content a.primitive{color:#32889b;}.content span.traitalias,.content a.traitalias{color:#57d399;}.content span.keyword,.content a.keyword{color:#de5249;}.content span.externcrate,.content span.mod,.content a.mod{color:#acccf9;}.content span.struct,.content a.struct{color:#ffa0a5;}.content span.enum,.content a.enum{color:#99e0c9;}.content span.trait,.content a.trait{color:#39AFD7;}.content span.type,.content a.type{color:#cfbcf5;}.content span.fn,.content a.fn,.content span.method,.content a.method,.content span.tymethod,.content a.tymethod,.content .fnname{color:#fdd687;}.content span.attr,.content a.attr,.content span.derive,.content a.derive,.content span.macro,.content a.macro{color:#a37acc;}pre.rust .comment{color:#788797;}pre.rust .doccomment{color:#a1ac88;}nav:not(.sidebar){border-bottom-color:#424c57;}nav.main .current{border-top-color:#5c6773;border-bottom-color:#5c6773;}nav.main .separator{border:1px solid #5c6773;}a{color:#c5c5c5;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#39AFD7;}details.rustdoc-toggle>summary.hideme>span,details.rustdoc-toggle>summary::before,details.undocumented>summary::before{color:#999;}#crate-search{color:#c5c5c5;background-color:#141920;box-shadow:0 0 0 1px #424c57,0 0 0 2px transparent;border-color:#424c57;}.search-input{color:#ffffff;background-color:#141920;box-shadow:0 0 0 1px #424c57,0 0 0 2px transparent;transition:box-shadow 150ms ease-in-out;}#crate-search+.search-input:focus{box-shadow:0 0 0 1px #148099,0 0 0 2px transparent;}.search-input:disabled{background-color:#3e3e3e;}.module-item .stab,.import-item .stab{color:#000;}.stab.unstable,.stab.deprecated,.stab.portability{color:#c5c5c5;background:#314559 !important;border-style:none !important;border-radius:4px;padding:3px 6px 3px 6px;}.stab.portability>code{color:#e6e1cf;background:none;}#help>div{background:#14191f;box-shadow:0px 6px 20px 0px black;border:none;border-radius:4px;}#help>div>span{border-bottom-color:#5c6773;}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:#788797;}.line-numbers :target{background-color:transparent;}pre.rust .number,pre.rust .string{color:#b8cc52;}pre.rust .kw,pre.rust .kw-2,pre.rust .prelude-ty,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .op,pre.rust .lifetime{color:#ff7733;}pre.rust .macro,pre.rust .macro-nonterminal{color:#a37acc;}pre.rust .question-mark{color:#ff9011;}pre.rust .self{color:#36a3d9;font-style:italic;}pre.rust .attribute{color:#e6e1cf;}pre.rust .attribute .ident,pre.rust .attribute .op{color:#e6e1cf;}.example-wrap>pre.line-number{color:#5c67736e;border:none;}a.test-arrow{font-size:100%;color:#788797;border-radius:4px;background-color:rgba(57,175,215,0.09);}a.test-arrow:hover{background-color:rgba(57,175,215,0.368);color:#c5c5c5;}.toggle-label,.code-attribute{color:#999;}:target,:target>*{background:rgba(255,236,164,0.06);border-right:3px solid rgba(255,180,76,0.85);}pre.compile_fail{border-left:2px solid rgba(255,0,0,.4);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.4);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.5);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.5);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#39AFD7;}.tooltip::after{background-color:#314559;color:#c5c5c5;border:1px solid #5c6773;}.tooltip::before{border-color:transparent #314559 transparent transparent;}.notable-traits-tooltiptext{background-color:#314559;border-color:#5c6773;}.notable-traits-tooltiptext .notable{border-bottom-color:#5c6773;}#titles>button.selected{background-color:#141920 !important;border-bottom:1px solid #ffb44c !important;border-top:none;}#titles>button:not(.selected){background-color:transparent !important;border:none;}#titles>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}#titles>button>div.count{color:#888;}.search-input:focus{}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{}.content span.struct,.content a.struct,.block a.current.struct{}#titles>button:hover,#titles>button.selected{}.content span.type,.content a.type,.block a.current.type{}.content span.union,.content a.union,.block a.current.union{}pre.rust .lifetime{}.stab.unstable{}h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod){}.content span.enum,.content a.enum,.block a.current.enum{}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{}.content span.keyword,.content a.keyword,.block a.current.keyword{}pre.rust .comment{}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{}pre.rust .kw{}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{}pre.rust .doccomment{}.stab.deprecated{}.content a.attr,.content a.derive,.content a.macro{}.stab.portability{}.content span.primitive,.content a.primitive,.block a.current.primitive{}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{}pre.rust .kw-2,pre.rust .prelude-ty{}.content span.trait,.content a.trait,.block a.current.trait{}.search-results a:focus span{}a.result-trait:focus{}a.result-traitalias:focus{}a.result-mod:focus,a.result-externcrate:focus{}a.result-mod:focus{}a.result-externcrate:focus{}a.result-enum:focus{}a.result-struct:focus{}a.result-union:focus{}a.result-fn:focus,a.result-method:focus,a.result-tymethod:focus{}a.result-type:focus{}a.result-foreigntype:focus{}a.result-attr:focus,a.result-derive:focus,a.result-macro:focus{}a.result-constant:focus,a.result-static:focus{}a.result-primitive:focus{}a.result-keyword:focus{}@media (max-width:700px){.sidebar-menu{background-color:#14191f;border-bottom-color:#5c6773;border-right-color:#5c6773;}.sidebar-elems{background-color:#14191f;border-right-color:#5c6773;}#sidebar-filler{background-color:#14191f;border-bottom-color:#5c6773;}}kbd{color:#c5c5c5;background-color:#314559;border-color:#5c6773;border-bottom-color:#5c6773;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,#help-button{border-color:#5c6773;background-color:#0f1419;color:#fff;}#theme-picker>img,#settings-menu>img{filter:invert(100);}#copy-path{color:#fff;}#copy-path>img{filter:invert(70%);}#copy-path:hover>img{filter:invert(100%);}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,#help-button:hover,#help-button:focus{border-color:#e0e0e0;}#theme-choices{border-color:#5c6773;background-color:#0f1419;}#theme-choices>button:not(:first-child){border-top-color:#5c6773;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:rgba(110,110,110,0.33);}@media (max-width:700px){#theme-picker{background:#0f1419;}}#all-types{background-color:#14191f;}#all-types:hover{background-color:rgba(70,70,70,0.33);}.search-results .result-name span.alias{color:#c5c5c5;}.search-results .result-name span.grey{color:#999;}#sidebar-toggle{background-color:#14191f;}#sidebar-toggle:hover{background-color:rgba(70,70,70,0.33);}#source-sidebar{background-color:#14191f;}#source-sidebar>.title{color:#fff;border-bottom-color:#5c6773;}div.files>a:hover,div.name:hover{background-color:#14191f;color:#ffb44c;}div.files>.selected{background-color:#14191f;color:#ffb44c;}.setting-line>.title{border-bottom-color:#5c6773;}input:checked+.slider{background-color:#ffb454 !important;} \ No newline at end of file diff --git a/base32/all.html b/base32/all.html new file mode 100644 index 000000000..86884341d --- /dev/null +++ b/base32/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/base32/fn.main.html b/base32/fn.main.html new file mode 100644 index 000000000..18305204a --- /dev/null +++ b/base32/fn.main.html @@ -0,0 +1,3 @@ +main in base32 - Rust + +

Function base32::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/base32/index.html b/base32/index.html new file mode 100644 index 000000000..ba83e0e39 --- /dev/null +++ b/base32/index.html @@ -0,0 +1,4 @@ +base32 - Rust + +

Crate base32[][src]

Functions

+
main
\ No newline at end of file diff --git a/base32/sidebar-items.js b/base32/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/base32/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/base64/all.html b/base64/all.html new file mode 100644 index 000000000..ad96aca46 --- /dev/null +++ b/base64/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/base64/fn.main.html b/base64/fn.main.html new file mode 100644 index 000000000..743bfebe4 --- /dev/null +++ b/base64/fn.main.html @@ -0,0 +1,3 @@ +main in base64 - Rust + +

Function base64::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/base64/index.html b/base64/index.html new file mode 100644 index 000000000..76fb4e060 --- /dev/null +++ b/base64/index.html @@ -0,0 +1,4 @@ +base64 - Rust + +

Crate base64[][src]

Functions

+
main
\ No newline at end of file diff --git a/base64/sidebar-items.js b/base64/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/base64/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/basename/all.html b/basename/all.html new file mode 100644 index 000000000..16807b908 --- /dev/null +++ b/basename/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/basename/fn.main.html b/basename/fn.main.html new file mode 100644 index 000000000..b1c1ea53d --- /dev/null +++ b/basename/fn.main.html @@ -0,0 +1,3 @@ +main in basename - Rust + +

Function basename::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/basename/index.html b/basename/index.html new file mode 100644 index 000000000..84e7cf4cd --- /dev/null +++ b/basename/index.html @@ -0,0 +1,4 @@ +basename - Rust + +

Crate basename[][src]

Functions

+
main
\ No newline at end of file diff --git a/basename/sidebar-items.js b/basename/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/basename/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/basenc/all.html b/basenc/all.html new file mode 100644 index 000000000..b06035e7a --- /dev/null +++ b/basenc/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/basenc/fn.main.html b/basenc/fn.main.html new file mode 100644 index 000000000..f45e8867d --- /dev/null +++ b/basenc/fn.main.html @@ -0,0 +1,3 @@ +main in basenc - Rust + +

Function basenc::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/basenc/index.html b/basenc/index.html new file mode 100644 index 000000000..025f264af --- /dev/null +++ b/basenc/index.html @@ -0,0 +1,4 @@ +basenc - Rust + +

Crate basenc[][src]

Functions

+
main
\ No newline at end of file diff --git a/basenc/sidebar-items.js b/basenc/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/basenc/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/brush.svg b/brush.svg new file mode 100644 index 000000000..ea266e856 --- /dev/null +++ b/brush.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/cat/all.html b/cat/all.html new file mode 100644 index 000000000..35e99cd16 --- /dev/null +++ b/cat/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/cat/fn.main.html b/cat/fn.main.html new file mode 100644 index 000000000..03ed631a9 --- /dev/null +++ b/cat/fn.main.html @@ -0,0 +1,3 @@ +main in cat - Rust + +

Function cat::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/cat/index.html b/cat/index.html new file mode 100644 index 000000000..3fad66e0f --- /dev/null +++ b/cat/index.html @@ -0,0 +1,4 @@ +cat - Rust + +

Crate cat[][src]

Functions

+
main
\ No newline at end of file diff --git a/cat/sidebar-items.js b/cat/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/cat/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/chcon/all.html b/chcon/all.html new file mode 100644 index 000000000..b1867ea56 --- /dev/null +++ b/chcon/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/chcon/fn.main.html b/chcon/fn.main.html new file mode 100644 index 000000000..1f587e049 --- /dev/null +++ b/chcon/fn.main.html @@ -0,0 +1,3 @@ +main in chcon - Rust + +

Function chcon::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/chcon/index.html b/chcon/index.html new file mode 100644 index 000000000..c258edc29 --- /dev/null +++ b/chcon/index.html @@ -0,0 +1,4 @@ +chcon - Rust + +

Crate chcon[][src]

Functions

+
main
\ No newline at end of file diff --git a/chcon/sidebar-items.js b/chcon/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/chcon/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/chgrp/all.html b/chgrp/all.html new file mode 100644 index 000000000..ad8963d73 --- /dev/null +++ b/chgrp/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/chgrp/fn.main.html b/chgrp/fn.main.html new file mode 100644 index 000000000..1e9af648c --- /dev/null +++ b/chgrp/fn.main.html @@ -0,0 +1,3 @@ +main in chgrp - Rust + +

Function chgrp::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/chgrp/index.html b/chgrp/index.html new file mode 100644 index 000000000..69010107c --- /dev/null +++ b/chgrp/index.html @@ -0,0 +1,4 @@ +chgrp - Rust + +

Crate chgrp[][src]

Functions

+
main
\ No newline at end of file diff --git a/chgrp/sidebar-items.js b/chgrp/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/chgrp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/chmod/all.html b/chmod/all.html new file mode 100644 index 000000000..55626baaa --- /dev/null +++ b/chmod/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/chmod/fn.main.html b/chmod/fn.main.html new file mode 100644 index 000000000..9d1ce4d5b --- /dev/null +++ b/chmod/fn.main.html @@ -0,0 +1,3 @@ +main in chmod - Rust + +

Function chmod::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/chmod/index.html b/chmod/index.html new file mode 100644 index 000000000..4188de47a --- /dev/null +++ b/chmod/index.html @@ -0,0 +1,4 @@ +chmod - Rust + +

Crate chmod[][src]

Functions

+
main
\ No newline at end of file diff --git a/chmod/sidebar-items.js b/chmod/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/chmod/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/chown/all.html b/chown/all.html new file mode 100644 index 000000000..a755c9a4b --- /dev/null +++ b/chown/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/chown/fn.main.html b/chown/fn.main.html new file mode 100644 index 000000000..d7eb1afa9 --- /dev/null +++ b/chown/fn.main.html @@ -0,0 +1,3 @@ +main in chown - Rust + +

Function chown::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/chown/index.html b/chown/index.html new file mode 100644 index 000000000..f4c724154 --- /dev/null +++ b/chown/index.html @@ -0,0 +1,4 @@ +chown - Rust + +

Crate chown[][src]

Functions

+
main
\ No newline at end of file diff --git a/chown/sidebar-items.js b/chown/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/chown/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/chroot/all.html b/chroot/all.html new file mode 100644 index 000000000..331f65781 --- /dev/null +++ b/chroot/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/chroot/fn.main.html b/chroot/fn.main.html new file mode 100644 index 000000000..b78c311af --- /dev/null +++ b/chroot/fn.main.html @@ -0,0 +1,3 @@ +main in chroot - Rust + +

Function chroot::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/chroot/index.html b/chroot/index.html new file mode 100644 index 000000000..59ca6fefd --- /dev/null +++ b/chroot/index.html @@ -0,0 +1,4 @@ +chroot - Rust + +

Crate chroot[][src]

Functions

+
main
\ No newline at end of file diff --git a/chroot/sidebar-items.js b/chroot/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/chroot/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/cksum/all.html b/cksum/all.html new file mode 100644 index 000000000..9c12d62ea --- /dev/null +++ b/cksum/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/cksum/fn.main.html b/cksum/fn.main.html new file mode 100644 index 000000000..ad03f43cc --- /dev/null +++ b/cksum/fn.main.html @@ -0,0 +1,3 @@ +main in cksum - Rust + +

Function cksum::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/cksum/index.html b/cksum/index.html new file mode 100644 index 000000000..72156ef5b --- /dev/null +++ b/cksum/index.html @@ -0,0 +1,4 @@ +cksum - Rust + +

Crate cksum[][src]

Functions

+
main
\ No newline at end of file diff --git a/cksum/sidebar-items.js b/cksum/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/cksum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/clipboard.svg b/clipboard.svg new file mode 100644 index 000000000..8adbd9963 --- /dev/null +++ b/clipboard.svg @@ -0,0 +1 @@ + diff --git a/comm/all.html b/comm/all.html new file mode 100644 index 000000000..3c3c0b314 --- /dev/null +++ b/comm/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/comm/fn.main.html b/comm/fn.main.html new file mode 100644 index 000000000..0e72a69da --- /dev/null +++ b/comm/fn.main.html @@ -0,0 +1,3 @@ +main in comm - Rust + +

Function comm::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/comm/index.html b/comm/index.html new file mode 100644 index 000000000..8dfb209a0 --- /dev/null +++ b/comm/index.html @@ -0,0 +1,4 @@ +comm - Rust + +

Crate comm[][src]

Functions

+
main
\ No newline at end of file diff --git a/comm/sidebar-items.js b/comm/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/comm/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/coreutils/all.html b/coreutils/all.html new file mode 100644 index 000000000..a0cf5d4e7 --- /dev/null +++ b/coreutils/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Typedefs

Constants

\ No newline at end of file diff --git a/coreutils/constant.VERSION.html b/coreutils/constant.VERSION.html new file mode 100644 index 000000000..27b03e682 --- /dev/null +++ b/coreutils/constant.VERSION.html @@ -0,0 +1,3 @@ +VERSION in coreutils - Rust + +

Constant coreutils::VERSION[][src]

pub(crate) const VERSION: &str = "0.0.7";
\ No newline at end of file diff --git a/coreutils/fn.binary_path.html b/coreutils/fn.binary_path.html new file mode 100644 index 000000000..133c950d1 --- /dev/null +++ b/coreutils/fn.binary_path.html @@ -0,0 +1,3 @@ +binary_path in coreutils - Rust + +

Function coreutils::binary_path[][src]

pub(crate) fn binary_path(args: &mut impl Iterator<Item = OsString>) -> PathBuf
\ No newline at end of file diff --git a/coreutils/fn.gen_completions.html b/coreutils/fn.gen_completions.html new file mode 100644 index 000000000..a4b911ada --- /dev/null +++ b/coreutils/fn.gen_completions.html @@ -0,0 +1,4 @@ +gen_completions in coreutils - Rust + +

Function coreutils::gen_completions[][src]

pub(crate) fn gen_completions<T: Args>(
    args: impl Iterator<Item = OsString>,
    util_map: HashMap<&'static str, (fn(_: T) -> i32, fn() -> App<'static, 'static>)>
) -> !
Expand description

Prints completions for the utility in the first parameter for the shell in the second parameter to stdout

+
\ No newline at end of file diff --git a/coreutils/fn.gen_coreutils_app.html b/coreutils/fn.gen_coreutils_app.html new file mode 100644 index 000000000..5399b1c69 --- /dev/null +++ b/coreutils/fn.gen_coreutils_app.html @@ -0,0 +1,3 @@ +gen_coreutils_app in coreutils - Rust + +

Function coreutils::gen_coreutils_app[][src]

pub(crate) fn gen_coreutils_app<T: Args>(
    util_map: HashMap<&'static str, (fn(_: T) -> i32, fn() -> App<'static, 'static>)>
) -> App<'static, 'static>
\ No newline at end of file diff --git a/coreutils/fn.main.html b/coreutils/fn.main.html new file mode 100644 index 000000000..9af6feff2 --- /dev/null +++ b/coreutils/fn.main.html @@ -0,0 +1,3 @@ +main in coreutils - Rust + +

Function coreutils::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/coreutils/fn.name.html b/coreutils/fn.name.html new file mode 100644 index 000000000..a1f4a9d46 --- /dev/null +++ b/coreutils/fn.name.html @@ -0,0 +1,3 @@ +name in coreutils - Rust + +

Function coreutils::name[][src]

pub(crate) fn name(binary_path: &Path) -> &str
\ No newline at end of file diff --git a/coreutils/fn.usage.html b/coreutils/fn.usage.html new file mode 100644 index 000000000..f93c8b32e --- /dev/null +++ b/coreutils/fn.usage.html @@ -0,0 +1,3 @@ +usage in coreutils - Rust + +

Function coreutils::usage[][src]

pub(crate) fn usage<T>(
    utils: &HashMap<&'static str, (fn(_: T) -> i32, fn() -> App<'static, 'static>)>,
    name: &str
)
\ No newline at end of file diff --git a/coreutils/fn.util_map.html b/coreutils/fn.util_map.html new file mode 100644 index 000000000..2872b57cb --- /dev/null +++ b/coreutils/fn.util_map.html @@ -0,0 +1,3 @@ +util_map in coreutils - Rust + +

Function coreutils::util_map[][src]

pub(crate) fn util_map<T: Args>(
) -> HashMap<&'static str, (fn(_: T) -> i32, fn() -> App<'static, 'static>)>
\ No newline at end of file diff --git a/coreutils/index.html b/coreutils/index.html new file mode 100644 index 000000000..7b7f09bbc --- /dev/null +++ b/coreutils/index.html @@ -0,0 +1,7 @@ +coreutils - Rust + +

Crate coreutils[][src]

Constants

+
VERSION

Functions

+
binary_path
gen_completions

Prints completions for the utility in the first parameter for the shell in the second parameter to stdout

+
gen_coreutils_app
main
name
usage
util_map

Type Definitions

+
UtilityMap
\ No newline at end of file diff --git a/coreutils/sidebar-items.js b/coreutils/sidebar-items.js new file mode 100644 index 000000000..21769c91b --- /dev/null +++ b/coreutils/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["VERSION",""]],"fn":[["binary_path",""],["gen_completions","Prints completions for the utility in the first parameter for the shell in the second parameter to stdout"],["gen_coreutils_app",""],["main",""],["name",""],["usage",""],["util_map",""]],"type":[["UtilityMap",""]]}); \ No newline at end of file diff --git a/coreutils/type.UtilityMap.html b/coreutils/type.UtilityMap.html new file mode 100644 index 000000000..52455321e --- /dev/null +++ b/coreutils/type.UtilityMap.html @@ -0,0 +1,3 @@ +UtilityMap in coreutils - Rust + +

Type Definition coreutils::UtilityMap[][src]

type UtilityMap<T> = HashMap<&'static str, (fn(_: T) -> i32, fn() -> App<'static, 'static>)>;
\ No newline at end of file diff --git a/cp/all.html b/cp/all.html new file mode 100644 index 000000000..b4014b466 --- /dev/null +++ b/cp/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/cp/fn.main.html b/cp/fn.main.html new file mode 100644 index 000000000..89f96f386 --- /dev/null +++ b/cp/fn.main.html @@ -0,0 +1,3 @@ +main in cp - Rust + +

Function cp::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/cp/index.html b/cp/index.html new file mode 100644 index 000000000..ef4436b78 --- /dev/null +++ b/cp/index.html @@ -0,0 +1,4 @@ +cp - Rust + +

Crate cp[][src]

Functions

+
main
\ No newline at end of file diff --git a/cp/sidebar-items.js b/cp/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/cp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/crates.js b/crates.js new file mode 100644 index 000000000..e47e427d1 --- /dev/null +++ b/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["arch","base32","base64","basename","basenc","cat","chcon","chgrp","chmod","chown","chroot","cksum","comm","coreutils","cp","csplit","cut","date","dd","df","dircolors","dirname","du","echo","env","expand","expr","factor","false","fmt","fold","groups","hashsum","head","hostid","hostname","id","install","join","kill","libstdbuf","link","ln","logname","ls","mkdir","mkfifo","mknod","mktemp","more","mv","nice","nl","nohup","nproc","numfmt","od","paste","pathchk","pinky","pr","printenv","printf","ptx","pwd","readlink","realpath","relpath","rm","rmdir","runcon","seq","shred","shuf","sleep","sort","split","stat","stdbuf","sum","sync","tac","tail","tee","test","timeout","touch","tr","true","truncate","tsort","tty","uname","unexpand","uniq","unlink","uptime","users","uu_arch","uu_base32","uu_base64","uu_basename","uu_basenc","uu_cat","uu_chcon","uu_chgrp","uu_chmod","uu_chown","uu_chroot","uu_cksum","uu_comm","uu_cp","uu_csplit","uu_cut","uu_date","uu_dd","uu_df","uu_dircolors","uu_dirname","uu_du","uu_echo","uu_env","uu_expand","uu_expr","uu_factor","uu_false","uu_fmt","uu_fold","uu_groups","uu_hashsum","uu_head","uu_hostid","uu_hostname","uu_id","uu_install","uu_join","uu_kill","uu_link","uu_ln","uu_logname","uu_ls","uu_mkdir","uu_mkfifo","uu_mknod","uu_mktemp","uu_more","uu_mv","uu_nice","uu_nl","uu_nohup","uu_nproc","uu_numfmt","uu_od","uu_paste","uu_pathchk","uu_pinky","uu_pr","uu_printenv","uu_printf","uu_ptx","uu_pwd","uu_readlink","uu_realpath","uu_relpath","uu_rm","uu_rmdir","uu_runcon","uu_seq","uu_shred","uu_shuf","uu_sleep","uu_sort","uu_split","uu_stat","uu_stdbuf","uu_sum","uu_sync","uu_tac","uu_tail","uu_tee","uu_test","uu_timeout","uu_touch","uu_tr","uu_true","uu_truncate","uu_tsort","uu_tty","uu_uname","uu_unexpand","uu_uniq","uu_unlink","uu_uptime","uu_users","uu_wc","uu_who","uu_whoami","uu_yes","uucore","uucore_procs","wc","who","whoami","yes"]; \ No newline at end of file diff --git a/csplit/all.html b/csplit/all.html new file mode 100644 index 000000000..172be6285 --- /dev/null +++ b/csplit/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/csplit/fn.main.html b/csplit/fn.main.html new file mode 100644 index 000000000..58177235b --- /dev/null +++ b/csplit/fn.main.html @@ -0,0 +1,3 @@ +main in csplit - Rust + +

Function csplit::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/csplit/index.html b/csplit/index.html new file mode 100644 index 000000000..ee7349102 --- /dev/null +++ b/csplit/index.html @@ -0,0 +1,4 @@ +csplit - Rust + +

Crate csplit[][src]

Functions

+
main
\ No newline at end of file diff --git a/csplit/sidebar-items.js b/csplit/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/csplit/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/cut/all.html b/cut/all.html new file mode 100644 index 000000000..6324fdf0b --- /dev/null +++ b/cut/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/cut/fn.main.html b/cut/fn.main.html new file mode 100644 index 000000000..167090b20 --- /dev/null +++ b/cut/fn.main.html @@ -0,0 +1,3 @@ +main in cut - Rust + +

Function cut::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/cut/index.html b/cut/index.html new file mode 100644 index 000000000..d3cd38744 --- /dev/null +++ b/cut/index.html @@ -0,0 +1,4 @@ +cut - Rust + +

Crate cut[][src]

Functions

+
main
\ No newline at end of file diff --git a/cut/sidebar-items.js b/cut/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/cut/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/dark.css b/dark.css new file mode 100644 index 000000000..227deb919 --- /dev/null +++ b/dark.css @@ -0,0 +1 @@ +body{background-color:#353535;color:#ddd;}h1,h2,h3,h4{color:#ddd;}h1.fqn{border-bottom-color:#d2d2d2;}h2,h3,h4{border-bottom-color:#d2d2d2;}.in-band{background-color:#353535;}.invisible{background:rgba(0,0,0,0);}.docblock code,.docblock-short code{background-color:#2A2A2A;}pre,.rustdoc.source .example-wrap{background-color:#2A2A2A;}.sidebar{background-color:#505050;}.logo-container.rust-logo>img{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff)}*{scrollbar-color:rgb(64,65,67) #717171;}.sidebar{scrollbar-color:rgba(32,34,37,.6) transparent;}::-webkit-scrollbar-track{background-color:#717171;}::-webkit-scrollbar-thumb{background-color:rgba(32,34,37,.6);}.sidebar::-webkit-scrollbar-track{background-color:#717171;}.sidebar::-webkit-scrollbar-thumb{background-color:rgba(32,34,37,.6);}.sidebar .current{background-color:#333;}.source .sidebar{background-color:#353535;}.sidebar .location{border-color:#fff;background:#575757;color:#DDD;}.sidebar .version{border-bottom-color:#DDD;}.sidebar-title{border-top-color:#777;border-bottom-color:#777;}.block a:hover{background:#444;}.line-numbers span{color:#3B91E2;}.line-numbers .line-highlighted{background-color:#0a042f !important;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#DDD;}.docblock table,.docblock table td,.docblock table th{border-color:#ddd;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#ddd;}.search-results a:hover{background-color:#777;}.search-results a:focus{color:#eee !important;background-color:#616161;}.search-results a:focus span{color:#eee !important;}a.result-trait:focus{background-color:#013191;}a.result-traitalias:focus{background-color:#013191;}a.result-mod:focus,a.result-externcrate:focus{background-color:#afc6e4;}a.result-mod:focus{background-color:#803a1b;}a.result-externcrate:focus{background-color:#396bac;}a.result-enum:focus{background-color:#5b4e68;}a.result-struct:focus{background-color:#194e9f;}a.result-union:focus{background-color:#b7bd49;}a.result-fn:focus,a.result-method:focus,a.result-tymethod:focus{background-color:#4950ed;}a.result-type:focus{background-color:#38902c;}a.result-foreigntype:focus{background-color:#b200d6;}a.result-attr:focus,a.result-derive:focus,a.result-macro:focus{background-color:#217d1c;}a.result-constant:focus,a.result-static:focus{background-color:#0063cc;}a.result-primitive:focus{background-color:#00708a;}a.result-keyword:focus{background-color:#884719;}.content .item-info::before{color:#ccc;}.content span.enum,.content a.enum,.block a.current.enum{color:#82b089;}.content span.struct,.content a.struct,.block a.current.struct{color:#2dbfb8;}.content span.type,.content a.type,.block a.current.type{color:#ff7f00;}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{color:#dd7de8;}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{color:#09bd00;}.content span.union,.content a.union,.block a.current.union{color:#a6ae37;}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{color:#82a5c9;}.content span.primitive,.content a.primitive,.block a.current.primitive{color:#43aec7;}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{color:#bda000;}.content span.trait,.content a.trait,.block a.current.trait{color:#b78cf2;}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{color:#b397da;}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{color:#2BAB63;}.content span.keyword,.content a.keyword,.block a.current.keyword{color:#de5249;}pre.rust .comment{color:#8d8d8b;}pre.rust .doccomment{color:#8ca375;}nav:not(.sidebar){border-bottom-color:#4e4e4e;}nav.main .current{border-top-color:#eee;border-bottom-color:#eee;}nav.main .separator{border-color:#eee;}a{color:#ddd;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#D2991D;}a.test-arrow{color:#dedede;}details.rustdoc-toggle>summary.hideme>span,details.rustdoc-toggle>summary::before,details.undocumented>summary::before{color:#999;}#crate-search{color:#111;background-color:#f0f0f0;border-color:#000;box-shadow:0 0 0 1px #000,0 0 0 2px transparent;}.search-input{color:#111;background-color:#f0f0f0;box-shadow:0 0 0 1px #000,0 0 0 2px transparent;}.search-input:focus{border-color:#008dfd;}.search-input:disabled{background-color:#c5c4c4;}#crate-search+.search-input:focus{box-shadow:0 0 8px 4px #078dd8;}.module-item .stab,.import-item .stab{color:#ddd;}.stab.unstable{background:#FFF5D6;border-color:#FFC600;color:#2f2f2f;}.stab.deprecated{background:#ffc4c4;border-color:#db7b7b;color:#2f2f2f;}.stab.portability{background:#F3DFFF;border-color:#b07bdb;color:#2f2f2f;}.stab.portability>code{background:none;}#help>div{background:#4d4d4d;border-color:#bfbfbf;}#help>div>span{border-bottom-color:#bfbfbf;}#help dt{border-color:#bfbfbf;background:rgba(0,0,0,0);}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:#ddd;}.line-numbers :target{background-color:transparent;}pre.rust .kw{color:#ab8ac1;}pre.rust .kw-2,pre.rust .prelude-ty{color:#769acb;}pre.rust .number,pre.rust .string{color:#83a300;}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{color:#ee6868;}pre.rust .macro,pre.rust .macro-nonterminal{color:#3E999F;}pre.rust .lifetime{color:#d97f26;}pre.rust .question-mark{color:#ff9011;}.example-wrap>pre.line-number{border-color:#4a4949;}a.test-arrow{background-color:rgba(78,139,202,0.2);}a.test-arrow:hover{background-color:#4e8bca;}.toggle-label,.code-attribute{color:#999;}:target,:target>*{background-color:#494a3d;}pre.compile_fail{border-left:2px solid rgba(255,0,0,.8);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.8);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.8);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.8);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#0089ff;}.tooltip::after{background-color:#000;color:#fff;border-color:#000;}.tooltip::before{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#111;border-color:#777;}.notable-traits-tooltiptext .notable{border-bottom-color:#d2d2d2;}#titles>button:not(.selected){background-color:#252525;border-top-color:#252525;}#titles>button:hover,#titles>button.selected{border-top-color:#0089ff;background-color:#353535;}#titles>button>div.count{color:#888;}@media (max-width:700px){.sidebar-menu{background-color:#505050;border-bottom-color:#e0e0e0;border-right-color:#e0e0e0;}.sidebar-elems{background-color:#505050;border-right-color:#000;}#sidebar-filler{background-color:#505050;border-bottom-color:#e0e0e0;}}kbd{color:#000;background-color:#fafbfc;border-color:#d1d5da;border-bottom-color:#c6cbd1;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,#help-button{border-color:#e0e0e0;background:#f0f0f0;color:#000;}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,#help-button:hover,#help-button:focus{border-color:#ffb900;}#copy-path{color:#999;}#copy-path>img{filter:invert(50%);}#copy-path:hover>img{filter:invert(65%);}#theme-choices{border-color:#e0e0e0;background-color:#353535;}#theme-choices>button:not(:first-child){border-top-color:#e0e0e0;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:#4e4e4e;}@media (max-width:700px){#theme-picker{background:#f0f0f0;}}#all-types{background-color:#505050;}#all-types:hover{background-color:#606060;}.search-results .result-name span.alias{color:#fff;}.search-results .result-name span.grey{color:#ccc;}#sidebar-toggle{background-color:#565656;}#sidebar-toggle:hover{background-color:#676767;}#source-sidebar{background-color:#565656;}#source-sidebar>.title{border-bottom-color:#ccc;}div.files>a:hover,div.name:hover{background-color:#444;}div.files>.selected{background-color:#333;}.setting-line>.title{border-bottom-color:#ddd;} \ No newline at end of file diff --git a/date/all.html b/date/all.html new file mode 100644 index 000000000..6c49b9d72 --- /dev/null +++ b/date/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/date/fn.main.html b/date/fn.main.html new file mode 100644 index 000000000..b7682ef3b --- /dev/null +++ b/date/fn.main.html @@ -0,0 +1,3 @@ +main in date - Rust + +

Function date::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/date/index.html b/date/index.html new file mode 100644 index 000000000..5b7a91603 --- /dev/null +++ b/date/index.html @@ -0,0 +1,4 @@ +date - Rust + +

Crate date[][src]

Functions

+
main
\ No newline at end of file diff --git a/date/sidebar-items.js b/date/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/date/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/dd/all.html b/dd/all.html new file mode 100644 index 000000000..0c09e3dc5 --- /dev/null +++ b/dd/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/dd/fn.main.html b/dd/fn.main.html new file mode 100644 index 000000000..a8c4c7996 --- /dev/null +++ b/dd/fn.main.html @@ -0,0 +1,3 @@ +main in dd - Rust + +

Function dd::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/dd/index.html b/dd/index.html new file mode 100644 index 000000000..27454a57e --- /dev/null +++ b/dd/index.html @@ -0,0 +1,4 @@ +dd - Rust + +

Crate dd[][src]

Functions

+
main
\ No newline at end of file diff --git a/dd/sidebar-items.js b/dd/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/dd/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/df/all.html b/df/all.html new file mode 100644 index 000000000..d39a4a8b9 --- /dev/null +++ b/df/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/df/fn.main.html b/df/fn.main.html new file mode 100644 index 000000000..76c3ef519 --- /dev/null +++ b/df/fn.main.html @@ -0,0 +1,3 @@ +main in df - Rust + +

Function df::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/df/index.html b/df/index.html new file mode 100644 index 000000000..52ad7c7e4 --- /dev/null +++ b/df/index.html @@ -0,0 +1,4 @@ +df - Rust + +

Crate df[][src]

Functions

+
main
\ No newline at end of file diff --git a/df/sidebar-items.js b/df/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/df/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/dircolors/all.html b/dircolors/all.html new file mode 100644 index 000000000..fbf0ad62a --- /dev/null +++ b/dircolors/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/dircolors/fn.main.html b/dircolors/fn.main.html new file mode 100644 index 000000000..dfc4f8b51 --- /dev/null +++ b/dircolors/fn.main.html @@ -0,0 +1,3 @@ +main in dircolors - Rust + +

Function dircolors::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/dircolors/index.html b/dircolors/index.html new file mode 100644 index 000000000..bea0f934d --- /dev/null +++ b/dircolors/index.html @@ -0,0 +1,4 @@ +dircolors - Rust + +

Crate dircolors[][src]

Functions

+
main
\ No newline at end of file diff --git a/dircolors/sidebar-items.js b/dircolors/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/dircolors/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/dirname/all.html b/dirname/all.html new file mode 100644 index 000000000..a6a672c0a --- /dev/null +++ b/dirname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/dirname/fn.main.html b/dirname/fn.main.html new file mode 100644 index 000000000..f9cf57866 --- /dev/null +++ b/dirname/fn.main.html @@ -0,0 +1,3 @@ +main in dirname - Rust + +

Function dirname::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/dirname/index.html b/dirname/index.html new file mode 100644 index 000000000..334008f9f --- /dev/null +++ b/dirname/index.html @@ -0,0 +1,4 @@ +dirname - Rust + +

Crate dirname[][src]

Functions

+
main
\ No newline at end of file diff --git a/dirname/sidebar-items.js b/dirname/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/dirname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/down-arrow.svg b/down-arrow.svg new file mode 100644 index 000000000..35437e77a --- /dev/null +++ b/down-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/du/all.html b/du/all.html new file mode 100644 index 000000000..d361385f4 --- /dev/null +++ b/du/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/du/fn.main.html b/du/fn.main.html new file mode 100644 index 000000000..a1189ce2a --- /dev/null +++ b/du/fn.main.html @@ -0,0 +1,3 @@ +main in du - Rust + +

Function du::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/du/index.html b/du/index.html new file mode 100644 index 000000000..8bac33022 --- /dev/null +++ b/du/index.html @@ -0,0 +1,4 @@ +du - Rust + +

Crate du[][src]

Functions

+
main
\ No newline at end of file diff --git a/du/sidebar-items.js b/du/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/du/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/echo/all.html b/echo/all.html new file mode 100644 index 000000000..3ef1924fd --- /dev/null +++ b/echo/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/echo/fn.main.html b/echo/fn.main.html new file mode 100644 index 000000000..f56b5d4de --- /dev/null +++ b/echo/fn.main.html @@ -0,0 +1,3 @@ +main in echo - Rust + +

Function echo::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/echo/index.html b/echo/index.html new file mode 100644 index 000000000..da3cd7a23 --- /dev/null +++ b/echo/index.html @@ -0,0 +1,4 @@ +echo - Rust + +

Crate echo[][src]

Functions

+
main
\ No newline at end of file diff --git a/echo/sidebar-items.js b/echo/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/echo/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/env/all.html b/env/all.html new file mode 100644 index 000000000..9dbef142b --- /dev/null +++ b/env/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/env/fn.main.html b/env/fn.main.html new file mode 100644 index 000000000..5cde76e13 --- /dev/null +++ b/env/fn.main.html @@ -0,0 +1,3 @@ +main in env - Rust + +

Function env::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/env/index.html b/env/index.html new file mode 100644 index 000000000..41923618f --- /dev/null +++ b/env/index.html @@ -0,0 +1,4 @@ +env - Rust + +

Crate env[][src]

Functions

+
main
\ No newline at end of file diff --git a/env/sidebar-items.js b/env/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/env/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/expand/all.html b/expand/all.html new file mode 100644 index 000000000..2d3efc710 --- /dev/null +++ b/expand/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/expand/fn.main.html b/expand/fn.main.html new file mode 100644 index 000000000..cd28cb165 --- /dev/null +++ b/expand/fn.main.html @@ -0,0 +1,3 @@ +main in expand - Rust + +

Function expand::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/expand/index.html b/expand/index.html new file mode 100644 index 000000000..f931a6703 --- /dev/null +++ b/expand/index.html @@ -0,0 +1,4 @@ +expand - Rust + +

Crate expand[][src]

Functions

+
main
\ No newline at end of file diff --git a/expand/sidebar-items.js b/expand/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/expand/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/expr/all.html b/expr/all.html new file mode 100644 index 000000000..f3a52968b --- /dev/null +++ b/expr/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/expr/fn.main.html b/expr/fn.main.html new file mode 100644 index 000000000..cd401d912 --- /dev/null +++ b/expr/fn.main.html @@ -0,0 +1,3 @@ +main in expr - Rust + +

Function expr::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/expr/index.html b/expr/index.html new file mode 100644 index 000000000..d605bb33c --- /dev/null +++ b/expr/index.html @@ -0,0 +1,4 @@ +expr - Rust + +

Crate expr[][src]

Functions

+
main
\ No newline at end of file diff --git a/expr/sidebar-items.js b/expr/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/expr/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/factor/all.html b/factor/all.html new file mode 100644 index 000000000..3c36c18c0 --- /dev/null +++ b/factor/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/factor/fn.main.html b/factor/fn.main.html new file mode 100644 index 000000000..333ac5ec8 --- /dev/null +++ b/factor/fn.main.html @@ -0,0 +1,3 @@ +main in factor - Rust + +

Function factor::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/factor/index.html b/factor/index.html new file mode 100644 index 000000000..652860e92 --- /dev/null +++ b/factor/index.html @@ -0,0 +1,4 @@ +factor - Rust + +

Crate factor[][src]

Functions

+
main
\ No newline at end of file diff --git a/factor/sidebar-items.js b/factor/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/factor/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/false/all.html b/false/all.html new file mode 100644 index 000000000..afa9270e9 --- /dev/null +++ b/false/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/false/fn.main.html b/false/fn.main.html new file mode 100644 index 000000000..e931ecead --- /dev/null +++ b/false/fn.main.html @@ -0,0 +1,3 @@ +main in false - Rust + +

Function false::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/false/index.html b/false/index.html new file mode 100644 index 000000000..586fabdb7 --- /dev/null +++ b/false/index.html @@ -0,0 +1,4 @@ +false - Rust + +

Crate false[][src]

Functions

+
main
\ No newline at end of file diff --git a/false/sidebar-items.js b/false/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/false/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 000000000..7cfe6c135 Binary files /dev/null and b/favicon-16x16.png differ diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 000000000..5109c1de8 Binary files /dev/null and b/favicon-32x32.png differ diff --git a/favicon.svg b/favicon.svg new file mode 100644 index 000000000..8b34b5119 --- /dev/null +++ b/favicon.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/fmt/all.html b/fmt/all.html new file mode 100644 index 000000000..39adb9852 --- /dev/null +++ b/fmt/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/fmt/fn.main.html b/fmt/fn.main.html new file mode 100644 index 000000000..feeb3d2e5 --- /dev/null +++ b/fmt/fn.main.html @@ -0,0 +1,3 @@ +main in fmt - Rust + +

Function fmt::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/fmt/index.html b/fmt/index.html new file mode 100644 index 000000000..a805bba7a --- /dev/null +++ b/fmt/index.html @@ -0,0 +1,4 @@ +fmt - Rust + +

Crate fmt[][src]

Functions

+
main
\ No newline at end of file diff --git a/fmt/sidebar-items.js b/fmt/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/fmt/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/fold/all.html b/fold/all.html new file mode 100644 index 000000000..82efe68ed --- /dev/null +++ b/fold/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/fold/fn.main.html b/fold/fn.main.html new file mode 100644 index 000000000..bdf5e90e1 --- /dev/null +++ b/fold/fn.main.html @@ -0,0 +1,3 @@ +main in fold - Rust + +

Function fold::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/fold/index.html b/fold/index.html new file mode 100644 index 000000000..1906a5ecb --- /dev/null +++ b/fold/index.html @@ -0,0 +1,4 @@ +fold - Rust + +

Crate fold[][src]

Functions

+
main
\ No newline at end of file diff --git a/fold/sidebar-items.js b/fold/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/fold/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/groups/all.html b/groups/all.html new file mode 100644 index 000000000..b4d684197 --- /dev/null +++ b/groups/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/groups/fn.main.html b/groups/fn.main.html new file mode 100644 index 000000000..b2b2e82ca --- /dev/null +++ b/groups/fn.main.html @@ -0,0 +1,3 @@ +main in groups - Rust + +

Function groups::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/groups/index.html b/groups/index.html new file mode 100644 index 000000000..c055e491f --- /dev/null +++ b/groups/index.html @@ -0,0 +1,4 @@ +groups - Rust + +

Crate groups[][src]

Functions

+
main
\ No newline at end of file diff --git a/groups/sidebar-items.js b/groups/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/groups/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/hashsum/all.html b/hashsum/all.html new file mode 100644 index 000000000..1dcdd3060 --- /dev/null +++ b/hashsum/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/hashsum/fn.main.html b/hashsum/fn.main.html new file mode 100644 index 000000000..c3339b115 --- /dev/null +++ b/hashsum/fn.main.html @@ -0,0 +1,3 @@ +main in hashsum - Rust + +

Function hashsum::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/hashsum/index.html b/hashsum/index.html new file mode 100644 index 000000000..6c2157b3f --- /dev/null +++ b/hashsum/index.html @@ -0,0 +1,4 @@ +hashsum - Rust + +

Crate hashsum[][src]

Functions

+
main
\ No newline at end of file diff --git a/hashsum/sidebar-items.js b/hashsum/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/hashsum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/head/all.html b/head/all.html new file mode 100644 index 000000000..08285dbd0 --- /dev/null +++ b/head/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/head/fn.main.html b/head/fn.main.html new file mode 100644 index 000000000..5325723ee --- /dev/null +++ b/head/fn.main.html @@ -0,0 +1,3 @@ +main in head - Rust + +

Function head::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/head/index.html b/head/index.html new file mode 100644 index 000000000..2b78dc4d5 --- /dev/null +++ b/head/index.html @@ -0,0 +1,4 @@ +head - Rust + +

Crate head[][src]

Functions

+
main
\ No newline at end of file diff --git a/head/sidebar-items.js b/head/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/head/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/hostid/all.html b/hostid/all.html new file mode 100644 index 000000000..20c0feaf2 --- /dev/null +++ b/hostid/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/hostid/fn.main.html b/hostid/fn.main.html new file mode 100644 index 000000000..e3e9991b3 --- /dev/null +++ b/hostid/fn.main.html @@ -0,0 +1,3 @@ +main in hostid - Rust + +

Function hostid::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/hostid/index.html b/hostid/index.html new file mode 100644 index 000000000..6c88ef75b --- /dev/null +++ b/hostid/index.html @@ -0,0 +1,4 @@ +hostid - Rust + +

Crate hostid[][src]

Functions

+
main
\ No newline at end of file diff --git a/hostid/sidebar-items.js b/hostid/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/hostid/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/hostname/all.html b/hostname/all.html new file mode 100644 index 000000000..5d40cf8aa --- /dev/null +++ b/hostname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/hostname/fn.main.html b/hostname/fn.main.html new file mode 100644 index 000000000..c61117334 --- /dev/null +++ b/hostname/fn.main.html @@ -0,0 +1,3 @@ +main in hostname - Rust + +

Function hostname::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/hostname/index.html b/hostname/index.html new file mode 100644 index 000000000..641ca30d9 --- /dev/null +++ b/hostname/index.html @@ -0,0 +1,4 @@ +hostname - Rust + +

Crate hostname[][src]

Functions

+
main
\ No newline at end of file diff --git a/hostname/sidebar-items.js b/hostname/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/hostname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/id/all.html b/id/all.html new file mode 100644 index 000000000..453d5f50e --- /dev/null +++ b/id/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/id/fn.main.html b/id/fn.main.html new file mode 100644 index 000000000..d69fdaf34 --- /dev/null +++ b/id/fn.main.html @@ -0,0 +1,3 @@ +main in id - Rust + +

Function id::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/id/index.html b/id/index.html new file mode 100644 index 000000000..d82d767f6 --- /dev/null +++ b/id/index.html @@ -0,0 +1,4 @@ +id - Rust + +

Crate id[][src]

Functions

+
main
\ No newline at end of file diff --git a/id/sidebar-items.js b/id/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/id/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/implementors/core/clone/trait.Clone.js b/implementors/core/clone/trait.Clone.js new file mode 100644 index 000000000..82aef4873 --- /dev/null +++ b/implementors/core/clone/trait.Clone.js @@ -0,0 +1,11 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl Clone for ClobberMode","synthetic":false,"types":["uu_cp::ClobberMode"]},{"text":"impl Clone for OverwriteMode","synthetic":false,"types":["uu_cp::OverwriteMode"]},{"text":"impl Clone for ReflinkMode","synthetic":false,"types":["uu_cp::ReflinkMode"]},{"text":"impl Clone for Attribute","synthetic":false,"types":["uu_cp::Attribute"]}]; +implementors["uu_factor"] = [{"text":"impl Clone for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_install"] = [{"text":"impl Clone for MainFunction","synthetic":false,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl Clone for Mode","synthetic":false,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl Clone for OverwriteMode","synthetic":false,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl Clone for OverwriteMode","synthetic":false,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_numfmt"] = [{"text":"impl Clone for RoundMethod","synthetic":false,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl Clone for GlobalSettings","synthetic":false,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> Clone for Line<'a>","synthetic":false,"types":["uu_sort::Line"]},{"text":"impl Clone for GeneralF64ParseResult","synthetic":false,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uucore"] = [{"text":"impl Clone for Format","synthetic":false,"types":["uucore::features::encoding::Format"]},{"text":"impl Clone for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Clone for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Clone for MountInfo","synthetic":false,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl Clone for FsUsage","synthetic":false,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl Clone for Passwd","synthetic":false,"types":["uucore::features::entries::Passwd"]},{"text":"impl Clone for VerbosityLevel","synthetic":false,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl Clone for Verbosity","synthetic":false,"types":["uucore::features::perms::Verbosity"]},{"text":"impl Clone for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Clone for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/cmp/trait.Eq.js b/implementors/core/cmp/trait.Eq.js new file mode 100644 index 000000000..93a4698d9 --- /dev/null +++ b/implementors/core/cmp/trait.Eq.js @@ -0,0 +1,8 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl Eq for ClobberMode","synthetic":false,"types":["uu_cp::ClobberMode"]},{"text":"impl Eq for OverwriteMode","synthetic":false,"types":["uu_cp::OverwriteMode"]},{"text":"impl Eq for ReflinkMode","synthetic":false,"types":["uu_cp::ReflinkMode"]},{"text":"impl Eq for Attribute","synthetic":false,"types":["uu_cp::Attribute"]}]; +implementors["uu_factor"] = [{"text":"impl Eq for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_install"] = [{"text":"impl Eq for MainFunction","synthetic":false,"types":["uu_install::MainFunction"]}]; +implementors["uu_ln"] = [{"text":"impl Eq for OverwriteMode","synthetic":false,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl Eq for OverwriteMode","synthetic":false,"types":["uu_mv::OverwriteMode"]}]; +implementors["uucore"] = [{"text":"impl Eq for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Eq for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Eq for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Eq for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl Eq for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]},{"text":"impl Eq for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/cmp/trait.Ord.js b/implementors/core/cmp/trait.Ord.js new file mode 100644 index 000000000..cd1353380 --- /dev/null +++ b/implementors/core/cmp/trait.Ord.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = [{"text":"impl Ord for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/cmp/trait.PartialEq.js b/implementors/core/cmp/trait.PartialEq.js new file mode 100644 index 000000000..6fea350ae --- /dev/null +++ b/implementors/core/cmp/trait.PartialEq.js @@ -0,0 +1,11 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl PartialEq<ClobberMode> for ClobberMode","synthetic":false,"types":["uu_cp::ClobberMode"]},{"text":"impl PartialEq<OverwriteMode> for OverwriteMode","synthetic":false,"types":["uu_cp::OverwriteMode"]},{"text":"impl PartialEq<ReflinkMode> for ReflinkMode","synthetic":false,"types":["uu_cp::ReflinkMode"]},{"text":"impl PartialEq<Attribute> for Attribute","synthetic":false,"types":["uu_cp::Attribute"]}]; +implementors["uu_dircolors"] = [{"text":"impl PartialEq<OutputFmt> for OutputFmt","synthetic":false,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl PartialEq<Factors> for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_install"] = [{"text":"impl PartialEq<MainFunction> for MainFunction","synthetic":false,"types":["uu_install::MainFunction"]}]; +implementors["uu_ln"] = [{"text":"impl PartialEq<OverwriteMode> for OverwriteMode","synthetic":false,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl PartialEq<OverwriteMode> for OverwriteMode","synthetic":false,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_sort"] = [{"text":"impl PartialEq<GeneralF64ParseResult> for GeneralF64ParseResult","synthetic":false,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl PartialEq<OutputType> for OutputType","synthetic":false,"types":["uu_stat::OutputType"]},{"text":"impl PartialEq<Token> for Token","synthetic":false,"types":["uu_stat::Token"]}]; +implementors["uucore"] = [{"text":"impl PartialEq<MissingHandling> for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl PartialEq<ResolveMode> for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl PartialEq<VerbosityLevel> for VerbosityLevel","synthetic":false,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl PartialEq<Verbosity> for Verbosity","synthetic":false,"types":["uucore::features::perms::Verbosity"]},{"text":"impl PartialEq<ExitStatus> for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl PartialEq<BackupMode> for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl PartialEq<Range> for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]},{"text":"impl PartialEq<ParseSizeError> for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/cmp/trait.PartialOrd.js b/implementors/core/cmp/trait.PartialOrd.js new file mode 100644 index 000000000..cff1d2aaf --- /dev/null +++ b/implementors/core/cmp/trait.PartialOrd.js @@ -0,0 +1,4 @@ +(function() {var implementors = {}; +implementors["uu_sort"] = [{"text":"impl PartialOrd<GeneralF64ParseResult> for GeneralF64ParseResult","synthetic":false,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uucore"] = [{"text":"impl PartialOrd<Range> for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/convert/trait.From.js b/implementors/core/convert/trait.From.js new file mode 100644 index 000000000..09cf46bd1 --- /dev/null +++ b/implementors/core/convert/trait.From.js @@ -0,0 +1,5 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl From<Error> for Error","synthetic":false,"types":["uu_cp::Error"]},{"text":"impl From<String> for Error","synthetic":false,"types":["uu_cp::Error"]},{"text":"impl From<&'static str> for Error","synthetic":false,"types":["uu_cp::Error"]},{"text":"impl From<Error> for Error","synthetic":false,"types":["uu_cp::Error"]},{"text":"impl From<StripPrefixError> for Error","synthetic":false,"types":["uu_cp::Error"]},{"text":"impl<'a> From<Context<&'a str, Error>> for Error","synthetic":false,"types":["uu_cp::Error"]}]; +implementors["uu_wc"] = [{"text":"impl From<Error> for WcError","synthetic":false,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl From<DecodeError> for DecodeError","synthetic":false,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl From<DecodeError> for DecodeError","synthetic":false,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl From<Error> for DecodeError","synthetic":false,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl<T> From<T> for Box<dyn UError> where
    T: UError + 'static, 
","synthetic":false,"types":["alloc::boxed::Box"]},{"text":"impl From<i32> for Box<dyn UError>","synthetic":false,"types":["alloc::boxed::Box"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/default/trait.Default.js b/implementors/core/default/trait.Default.js new file mode 100644 index 000000000..dd841ba03 --- /dev/null +++ b/implementors/core/default/trait.Default.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uu_sort"] = [{"text":"impl Default for GlobalSettings","synthetic":false,"types":["uu_sort::GlobalSettings"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/fmt/trait.Debug.js b/implementors/core/fmt/trait.Debug.js new file mode 100644 index 000000000..450785321 --- /dev/null +++ b/implementors/core/fmt/trait.Debug.js @@ -0,0 +1,10 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl Debug for Error","synthetic":false,"types":["uu_cp::Error"]}]; +implementors["uu_dircolors"] = [{"text":"impl Debug for OutputFmt","synthetic":false,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl Debug for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_ln"] = [{"text":"impl Debug for OverwriteMode","synthetic":false,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_sort"] = [{"text":"impl<'a> Debug for Line<'a>","synthetic":false,"types":["uu_sort::Line"]},{"text":"impl Debug for GeneralF64ParseResult","synthetic":false,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl Debug for OutputType","synthetic":false,"types":["uu_stat::OutputType"]},{"text":"impl Debug for Token","synthetic":false,"types":["uu_stat::Token"]}]; +implementors["uu_wc"] = [{"text":"impl Debug for WcError","synthetic":false,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Debug for DecodeError","synthetic":false,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Debug for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Debug for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Debug for MountInfo","synthetic":false,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl Debug for FsUsage","synthetic":false,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl Debug for VerbosityLevel","synthetic":false,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl Debug for Verbosity","synthetic":false,"types":["uucore::features::perms::Verbosity"]},{"text":"impl Debug for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Debug for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl Debug for USimpleError","synthetic":false,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Debug for UUsageError","synthetic":false,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Debug for UIoError","synthetic":false,"types":["uucore::mods::error::UIoError"]},{"text":"impl Debug for ExitCode","synthetic":false,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Debug for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]},{"text":"impl Debug for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/fmt/trait.Display.js b/implementors/core/fmt/trait.Display.js new file mode 100644 index 000000000..5f5856fcd --- /dev/null +++ b/implementors/core/fmt/trait.Display.js @@ -0,0 +1,6 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl Display for Error","synthetic":false,"types":["uu_cp::Error"]}]; +implementors["uu_factor"] = [{"text":"impl Display for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_wc"] = [{"text":"impl Display for WcError","synthetic":false,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Display for DecodeError","synthetic":false,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Display for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Display for USimpleError","synthetic":false,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Display for UUsageError","synthetic":false,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Display for UIoError","synthetic":false,"types":["uucore::mods::error::UIoError"]},{"text":"impl Display for ExitCode","synthetic":false,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Display for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/iter/traits/iterator/trait.Iterator.js b/implementors/core/iter/traits/iterator/trait.Iterator.js new file mode 100644 index 000000000..632321517 --- /dev/null +++ b/implementors/core/iter/traits/iterator/trait.Iterator.js @@ -0,0 +1,4 @@ +(function() {var implementors = {}; +implementors["uu_numfmt"] = [{"text":"impl<'a> Iterator for WhitespaceSplitter<'a>","synthetic":false,"types":["uu_numfmt::format::WhitespaceSplitter"]}]; +implementors["uucore"] = [{"text":"impl Iterator for UtmpxIter","synthetic":false,"types":["uucore::features::utmpx::UtmpxIter"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.Copy.js b/implementors/core/marker/trait.Copy.js new file mode 100644 index 000000000..2862ee525 --- /dev/null +++ b/implementors/core/marker/trait.Copy.js @@ -0,0 +1,7 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl Copy for ReflinkMode","synthetic":false,"types":["uu_cp::ReflinkMode"]}]; +implementors["uu_kill"] = [{"text":"impl Copy for Mode","synthetic":false,"types":["uu_kill::Mode"]}]; +implementors["uu_numfmt"] = [{"text":"impl Copy for RoundMethod","synthetic":false,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl Copy for GeneralF64ParseResult","synthetic":false,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uucore"] = [{"text":"impl Copy for Format","synthetic":false,"types":["uucore::features::encoding::Format"]},{"text":"impl Copy for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Copy for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Copy for Passwd","synthetic":false,"types":["uucore::features::entries::Passwd"]},{"text":"impl Copy for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Copy for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.Freeze.js b/implementors/core/marker/trait.Freeze.js new file mode 100644 index 000000000..020f0dca7 --- /dev/null +++ b/implementors/core/marker/trait.Freeze.js @@ -0,0 +1,18 @@ +(function() {var implementors = {}; +implementors["uu_base32"] = [{"text":"impl Freeze for Config","synthetic":true,"types":["uu_base32::base_common::Config"]}]; +implementors["uu_cp"] = [{"text":"impl Freeze for Error","synthetic":true,"types":["uu_cp::Error"]},{"text":"impl Freeze for ClobberMode","synthetic":true,"types":["uu_cp::ClobberMode"]},{"text":"impl Freeze for OverwriteMode","synthetic":true,"types":["uu_cp::OverwriteMode"]},{"text":"impl Freeze for ReflinkMode","synthetic":true,"types":["uu_cp::ReflinkMode"]},{"text":"impl Freeze for TargetType","synthetic":true,"types":["uu_cp::TargetType"]},{"text":"impl Freeze for CopyMode","synthetic":true,"types":["uu_cp::CopyMode"]},{"text":"impl Freeze for Attribute","synthetic":true,"types":["uu_cp::Attribute"]},{"text":"impl Freeze for Options","synthetic":true,"types":["uu_cp::Options"]}]; +implementors["uu_csplit"] = [{"text":"impl Freeze for CsplitOptions","synthetic":true,"types":["uu_csplit::CsplitOptions"]}]; +implementors["uu_dircolors"] = [{"text":"impl Freeze for OutputFmt","synthetic":true,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl !Freeze for Factors","synthetic":true,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_fmt"] = [{"text":"impl Freeze for FmtOptions","synthetic":true,"types":["uu_fmt::FmtOptions"]}]; +implementors["uu_install"] = [{"text":"impl Freeze for Behavior","synthetic":true,"types":["uu_install::Behavior"]},{"text":"impl Freeze for MainFunction","synthetic":true,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl Freeze for Mode","synthetic":true,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl Freeze for Settings","synthetic":true,"types":["uu_ln::Settings"]},{"text":"impl Freeze for OverwriteMode","synthetic":true,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl Freeze for Behavior","synthetic":true,"types":["uu_mv::Behavior"]},{"text":"impl Freeze for OverwriteMode","synthetic":true,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_nl"] = [{"text":"impl Freeze for Settings","synthetic":true,"types":["uu_nl::Settings"]}]; +implementors["uu_numfmt"] = [{"text":"impl<'a> Freeze for WhitespaceSplitter<'a>","synthetic":true,"types":["uu_numfmt::format::WhitespaceSplitter"]},{"text":"impl Freeze for TransformOptions","synthetic":true,"types":["uu_numfmt::options::TransformOptions"]},{"text":"impl Freeze for NumfmtOptions","synthetic":true,"types":["uu_numfmt::options::NumfmtOptions"]},{"text":"impl Freeze for RoundMethod","synthetic":true,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl Freeze for Output","synthetic":true,"types":["uu_sort::Output"]},{"text":"impl Freeze for GlobalSettings","synthetic":true,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> Freeze for Line<'a>","synthetic":true,"types":["uu_sort::Line"]},{"text":"impl Freeze for GeneralF64ParseResult","synthetic":true,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl Freeze for OutputType","synthetic":true,"types":["uu_stat::OutputType"]},{"text":"impl Freeze for Token","synthetic":true,"types":["uu_stat::Token"]},{"text":"impl Freeze for Stater","synthetic":true,"types":["uu_stat::Stater"]}]; +implementors["uu_wc"] = [{"text":"impl Freeze for WcError","synthetic":true,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Freeze for DecodeError","synthetic":true,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Freeze for EncodeError","synthetic":true,"types":["uucore::features::encoding::EncodeError"]},{"text":"impl Freeze for Format","synthetic":true,"types":["uucore::features::encoding::Format"]},{"text":"impl<R> Freeze for Data<R> where
    R: Freeze, 
","synthetic":true,"types":["uucore::features::encoding::Data"]},{"text":"impl Freeze for MissingHandling","synthetic":true,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Freeze for ResolveMode","synthetic":true,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Freeze for MountInfo","synthetic":true,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl Freeze for FsUsage","synthetic":true,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl<T> Freeze for RingBuffer<T>","synthetic":true,"types":["uucore::features::ringbuffer::RingBuffer"]},{"text":"impl<T> Freeze for ZeroCopyWriter<T> where
    T: Freeze, 
","synthetic":true,"types":["uucore::features::zero_copy::ZeroCopyWriter"]},{"text":"impl Freeze for Passwd","synthetic":true,"types":["uucore::features::entries::Passwd"]},{"text":"impl Freeze for Group","synthetic":true,"types":["uucore::features::entries::Group"]},{"text":"impl Freeze for VerbosityLevel","synthetic":true,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl Freeze for Verbosity","synthetic":true,"types":["uucore::features::perms::Verbosity"]},{"text":"impl Freeze for IfFrom","synthetic":true,"types":["uucore::features::perms::IfFrom"]},{"text":"impl Freeze for ChownExecutor","synthetic":true,"types":["uucore::features::perms::ChownExecutor"]},{"text":"impl Freeze for ExitStatus","synthetic":true,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Freeze for Utmpx","synthetic":true,"types":["uucore::features::utmpx::Utmpx"]},{"text":"impl Freeze for UtmpxIter","synthetic":true,"types":["uucore::features::utmpx::UtmpxIter"]},{"text":"impl Freeze for BackupMode","synthetic":true,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl<'a> Freeze for HelpText<'a>","synthetic":true,"types":["uucore::mods::coreopts::HelpText"]},{"text":"impl<'a> Freeze for CoreOptions<'a>","synthetic":true,"types":["uucore::mods::coreopts::CoreOptions"]},{"text":"impl Freeze for USimpleError","synthetic":true,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Freeze for UUsageError","synthetic":true,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Freeze for UIoError","synthetic":true,"types":["uucore::mods::error::UIoError"]},{"text":"impl Freeze for ExitCode","synthetic":true,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Freeze for Range","synthetic":true,"types":["uucore::mods::ranges::Range"]},{"text":"impl Freeze for ParseSizeError","synthetic":true,"types":["uucore::parser::parse_size::ParseSizeError"]},{"text":"impl Freeze for InvalidEncodingHandling","synthetic":true,"types":["uucore::InvalidEncodingHandling"]},{"text":"impl Freeze for ConversionResult","synthetic":true,"types":["uucore::ConversionResult"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.Send.js b/implementors/core/marker/trait.Send.js new file mode 100644 index 000000000..77b269ff1 --- /dev/null +++ b/implementors/core/marker/trait.Send.js @@ -0,0 +1,18 @@ +(function() {var implementors = {}; +implementors["uu_base32"] = [{"text":"impl Send for Config","synthetic":true,"types":["uu_base32::base_common::Config"]}]; +implementors["uu_cp"] = [{"text":"impl Send for Error","synthetic":true,"types":["uu_cp::Error"]},{"text":"impl Send for ClobberMode","synthetic":true,"types":["uu_cp::ClobberMode"]},{"text":"impl Send for OverwriteMode","synthetic":true,"types":["uu_cp::OverwriteMode"]},{"text":"impl Send for ReflinkMode","synthetic":true,"types":["uu_cp::ReflinkMode"]},{"text":"impl Send for TargetType","synthetic":true,"types":["uu_cp::TargetType"]},{"text":"impl Send for CopyMode","synthetic":true,"types":["uu_cp::CopyMode"]},{"text":"impl Send for Attribute","synthetic":true,"types":["uu_cp::Attribute"]},{"text":"impl Send for Options","synthetic":true,"types":["uu_cp::Options"]}]; +implementors["uu_csplit"] = [{"text":"impl !Send for CsplitOptions","synthetic":true,"types":["uu_csplit::CsplitOptions"]}]; +implementors["uu_dircolors"] = [{"text":"impl Send for OutputFmt","synthetic":true,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl Send for Factors","synthetic":true,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_fmt"] = [{"text":"impl Send for FmtOptions","synthetic":true,"types":["uu_fmt::FmtOptions"]}]; +implementors["uu_install"] = [{"text":"impl Send for Behavior","synthetic":true,"types":["uu_install::Behavior"]},{"text":"impl Send for MainFunction","synthetic":true,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl Send for Mode","synthetic":true,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl Send for Settings","synthetic":true,"types":["uu_ln::Settings"]},{"text":"impl Send for OverwriteMode","synthetic":true,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl Send for Behavior","synthetic":true,"types":["uu_mv::Behavior"]},{"text":"impl Send for OverwriteMode","synthetic":true,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_nl"] = [{"text":"impl Send for Settings","synthetic":true,"types":["uu_nl::Settings"]}]; +implementors["uu_numfmt"] = [{"text":"impl<'a> Send for WhitespaceSplitter<'a>","synthetic":true,"types":["uu_numfmt::format::WhitespaceSplitter"]},{"text":"impl Send for TransformOptions","synthetic":true,"types":["uu_numfmt::options::TransformOptions"]},{"text":"impl Send for NumfmtOptions","synthetic":true,"types":["uu_numfmt::options::NumfmtOptions"]},{"text":"impl Send for RoundMethod","synthetic":true,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl Send for Output","synthetic":true,"types":["uu_sort::Output"]},{"text":"impl Send for GlobalSettings","synthetic":true,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> Send for Line<'a>","synthetic":true,"types":["uu_sort::Line"]},{"text":"impl Send for GeneralF64ParseResult","synthetic":true,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl Send for OutputType","synthetic":true,"types":["uu_stat::OutputType"]},{"text":"impl Send for Token","synthetic":true,"types":["uu_stat::Token"]},{"text":"impl Send for Stater","synthetic":true,"types":["uu_stat::Stater"]}]; +implementors["uu_wc"] = [{"text":"impl Send for WcError","synthetic":true,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Send for DecodeError","synthetic":true,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Send for EncodeError","synthetic":true,"types":["uucore::features::encoding::EncodeError"]},{"text":"impl Send for Format","synthetic":true,"types":["uucore::features::encoding::Format"]},{"text":"impl<R> Send for Data<R> where
    R: Send
","synthetic":true,"types":["uucore::features::encoding::Data"]},{"text":"impl Send for MissingHandling","synthetic":true,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Send for ResolveMode","synthetic":true,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Send for MountInfo","synthetic":true,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl Send for FsUsage","synthetic":true,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl<T> Send for RingBuffer<T> where
    T: Send
","synthetic":true,"types":["uucore::features::ringbuffer::RingBuffer"]},{"text":"impl<T> Send for ZeroCopyWriter<T> where
    T: Send
","synthetic":true,"types":["uucore::features::zero_copy::ZeroCopyWriter"]},{"text":"impl !Send for Passwd","synthetic":true,"types":["uucore::features::entries::Passwd"]},{"text":"impl !Send for Group","synthetic":true,"types":["uucore::features::entries::Group"]},{"text":"impl Send for VerbosityLevel","synthetic":true,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl Send for Verbosity","synthetic":true,"types":["uucore::features::perms::Verbosity"]},{"text":"impl Send for IfFrom","synthetic":true,"types":["uucore::features::perms::IfFrom"]},{"text":"impl Send for ChownExecutor","synthetic":true,"types":["uucore::features::perms::ChownExecutor"]},{"text":"impl Send for ExitStatus","synthetic":true,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Send for Utmpx","synthetic":true,"types":["uucore::features::utmpx::Utmpx"]},{"text":"impl Send for UtmpxIter","synthetic":true,"types":["uucore::features::utmpx::UtmpxIter"]},{"text":"impl Send for BackupMode","synthetic":true,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl<'a> Send for HelpText<'a>","synthetic":true,"types":["uucore::mods::coreopts::HelpText"]},{"text":"impl<'a> Send for CoreOptions<'a>","synthetic":true,"types":["uucore::mods::coreopts::CoreOptions"]},{"text":"impl Send for USimpleError","synthetic":true,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Send for UUsageError","synthetic":true,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Send for UIoError","synthetic":true,"types":["uucore::mods::error::UIoError"]},{"text":"impl Send for ExitCode","synthetic":true,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Send for Range","synthetic":true,"types":["uucore::mods::ranges::Range"]},{"text":"impl Send for ParseSizeError","synthetic":true,"types":["uucore::parser::parse_size::ParseSizeError"]},{"text":"impl Send for InvalidEncodingHandling","synthetic":true,"types":["uucore::InvalidEncodingHandling"]},{"text":"impl Send for ConversionResult","synthetic":true,"types":["uucore::ConversionResult"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.StructuralEq.js b/implementors/core/marker/trait.StructuralEq.js new file mode 100644 index 000000000..e65caf6c9 --- /dev/null +++ b/implementors/core/marker/trait.StructuralEq.js @@ -0,0 +1,8 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl StructuralEq for ClobberMode","synthetic":false,"types":["uu_cp::ClobberMode"]},{"text":"impl StructuralEq for OverwriteMode","synthetic":false,"types":["uu_cp::OverwriteMode"]},{"text":"impl StructuralEq for ReflinkMode","synthetic":false,"types":["uu_cp::ReflinkMode"]},{"text":"impl StructuralEq for Attribute","synthetic":false,"types":["uu_cp::Attribute"]}]; +implementors["uu_factor"] = [{"text":"impl StructuralEq for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_install"] = [{"text":"impl StructuralEq for MainFunction","synthetic":false,"types":["uu_install::MainFunction"]}]; +implementors["uu_ln"] = [{"text":"impl StructuralEq for OverwriteMode","synthetic":false,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl StructuralEq for OverwriteMode","synthetic":false,"types":["uu_mv::OverwriteMode"]}]; +implementors["uucore"] = [{"text":"impl StructuralEq for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl StructuralEq for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl StructuralEq for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl StructuralEq for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl StructuralEq for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]},{"text":"impl StructuralEq for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.StructuralPartialEq.js b/implementors/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 000000000..90709748e --- /dev/null +++ b/implementors/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,11 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl StructuralPartialEq for ClobberMode","synthetic":false,"types":["uu_cp::ClobberMode"]},{"text":"impl StructuralPartialEq for OverwriteMode","synthetic":false,"types":["uu_cp::OverwriteMode"]},{"text":"impl StructuralPartialEq for ReflinkMode","synthetic":false,"types":["uu_cp::ReflinkMode"]},{"text":"impl StructuralPartialEq for Attribute","synthetic":false,"types":["uu_cp::Attribute"]}]; +implementors["uu_dircolors"] = [{"text":"impl StructuralPartialEq for OutputFmt","synthetic":false,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl StructuralPartialEq for Factors","synthetic":false,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_install"] = [{"text":"impl StructuralPartialEq for MainFunction","synthetic":false,"types":["uu_install::MainFunction"]}]; +implementors["uu_ln"] = [{"text":"impl StructuralPartialEq for OverwriteMode","synthetic":false,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl StructuralPartialEq for OverwriteMode","synthetic":false,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_sort"] = [{"text":"impl StructuralPartialEq for GeneralF64ParseResult","synthetic":false,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl StructuralPartialEq for OutputType","synthetic":false,"types":["uu_stat::OutputType"]},{"text":"impl StructuralPartialEq for Token","synthetic":false,"types":["uu_stat::Token"]}]; +implementors["uucore"] = [{"text":"impl StructuralPartialEq for MissingHandling","synthetic":false,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl StructuralPartialEq for ResolveMode","synthetic":false,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl StructuralPartialEq for VerbosityLevel","synthetic":false,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl StructuralPartialEq for Verbosity","synthetic":false,"types":["uucore::features::perms::Verbosity"]},{"text":"impl StructuralPartialEq for ExitStatus","synthetic":false,"types":["uucore::features::process::ExitStatus"]},{"text":"impl StructuralPartialEq for BackupMode","synthetic":false,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl StructuralPartialEq for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]},{"text":"impl StructuralPartialEq for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.Sync.js b/implementors/core/marker/trait.Sync.js new file mode 100644 index 000000000..35bb71397 --- /dev/null +++ b/implementors/core/marker/trait.Sync.js @@ -0,0 +1,18 @@ +(function() {var implementors = {}; +implementors["uu_base32"] = [{"text":"impl Sync for Config","synthetic":true,"types":["uu_base32::base_common::Config"]}]; +implementors["uu_cp"] = [{"text":"impl Sync for Error","synthetic":true,"types":["uu_cp::Error"]},{"text":"impl Sync for ClobberMode","synthetic":true,"types":["uu_cp::ClobberMode"]},{"text":"impl Sync for OverwriteMode","synthetic":true,"types":["uu_cp::OverwriteMode"]},{"text":"impl Sync for ReflinkMode","synthetic":true,"types":["uu_cp::ReflinkMode"]},{"text":"impl Sync for TargetType","synthetic":true,"types":["uu_cp::TargetType"]},{"text":"impl Sync for CopyMode","synthetic":true,"types":["uu_cp::CopyMode"]},{"text":"impl Sync for Attribute","synthetic":true,"types":["uu_cp::Attribute"]},{"text":"impl Sync for Options","synthetic":true,"types":["uu_cp::Options"]}]; +implementors["uu_csplit"] = [{"text":"impl !Sync for CsplitOptions","synthetic":true,"types":["uu_csplit::CsplitOptions"]}]; +implementors["uu_dircolors"] = [{"text":"impl Sync for OutputFmt","synthetic":true,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl !Sync for Factors","synthetic":true,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_fmt"] = [{"text":"impl Sync for FmtOptions","synthetic":true,"types":["uu_fmt::FmtOptions"]}]; +implementors["uu_install"] = [{"text":"impl Sync for Behavior","synthetic":true,"types":["uu_install::Behavior"]},{"text":"impl Sync for MainFunction","synthetic":true,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl Sync for Mode","synthetic":true,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl Sync for Settings","synthetic":true,"types":["uu_ln::Settings"]},{"text":"impl Sync for OverwriteMode","synthetic":true,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl Sync for Behavior","synthetic":true,"types":["uu_mv::Behavior"]},{"text":"impl Sync for OverwriteMode","synthetic":true,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_nl"] = [{"text":"impl Sync for Settings","synthetic":true,"types":["uu_nl::Settings"]}]; +implementors["uu_numfmt"] = [{"text":"impl<'a> Sync for WhitespaceSplitter<'a>","synthetic":true,"types":["uu_numfmt::format::WhitespaceSplitter"]},{"text":"impl Sync for TransformOptions","synthetic":true,"types":["uu_numfmt::options::TransformOptions"]},{"text":"impl Sync for NumfmtOptions","synthetic":true,"types":["uu_numfmt::options::NumfmtOptions"]},{"text":"impl Sync for RoundMethod","synthetic":true,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl Sync for Output","synthetic":true,"types":["uu_sort::Output"]},{"text":"impl Sync for GlobalSettings","synthetic":true,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> Sync for Line<'a>","synthetic":true,"types":["uu_sort::Line"]},{"text":"impl Sync for GeneralF64ParseResult","synthetic":true,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl Sync for OutputType","synthetic":true,"types":["uu_stat::OutputType"]},{"text":"impl Sync for Token","synthetic":true,"types":["uu_stat::Token"]},{"text":"impl Sync for Stater","synthetic":true,"types":["uu_stat::Stater"]}]; +implementors["uu_wc"] = [{"text":"impl Sync for WcError","synthetic":true,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Sync for DecodeError","synthetic":true,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Sync for EncodeError","synthetic":true,"types":["uucore::features::encoding::EncodeError"]},{"text":"impl Sync for Format","synthetic":true,"types":["uucore::features::encoding::Format"]},{"text":"impl<R> Sync for Data<R> where
    R: Sync
","synthetic":true,"types":["uucore::features::encoding::Data"]},{"text":"impl Sync for MissingHandling","synthetic":true,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Sync for ResolveMode","synthetic":true,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Sync for MountInfo","synthetic":true,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl Sync for FsUsage","synthetic":true,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl<T> Sync for RingBuffer<T> where
    T: Sync
","synthetic":true,"types":["uucore::features::ringbuffer::RingBuffer"]},{"text":"impl<T> Sync for ZeroCopyWriter<T> where
    T: Sync
","synthetic":true,"types":["uucore::features::zero_copy::ZeroCopyWriter"]},{"text":"impl !Sync for Passwd","synthetic":true,"types":["uucore::features::entries::Passwd"]},{"text":"impl !Sync for Group","synthetic":true,"types":["uucore::features::entries::Group"]},{"text":"impl Sync for VerbosityLevel","synthetic":true,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl Sync for Verbosity","synthetic":true,"types":["uucore::features::perms::Verbosity"]},{"text":"impl Sync for IfFrom","synthetic":true,"types":["uucore::features::perms::IfFrom"]},{"text":"impl Sync for ChownExecutor","synthetic":true,"types":["uucore::features::perms::ChownExecutor"]},{"text":"impl Sync for ExitStatus","synthetic":true,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Sync for Utmpx","synthetic":true,"types":["uucore::features::utmpx::Utmpx"]},{"text":"impl Sync for UtmpxIter","synthetic":true,"types":["uucore::features::utmpx::UtmpxIter"]},{"text":"impl Sync for BackupMode","synthetic":true,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl<'a> Sync for HelpText<'a>","synthetic":true,"types":["uucore::mods::coreopts::HelpText"]},{"text":"impl<'a> Sync for CoreOptions<'a>","synthetic":true,"types":["uucore::mods::coreopts::CoreOptions"]},{"text":"impl Sync for USimpleError","synthetic":true,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Sync for UUsageError","synthetic":true,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Sync for UIoError","synthetic":true,"types":["uucore::mods::error::UIoError"]},{"text":"impl Sync for ExitCode","synthetic":true,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Sync for Range","synthetic":true,"types":["uucore::mods::ranges::Range"]},{"text":"impl Sync for ParseSizeError","synthetic":true,"types":["uucore::parser::parse_size::ParseSizeError"]},{"text":"impl Sync for InvalidEncodingHandling","synthetic":true,"types":["uucore::InvalidEncodingHandling"]},{"text":"impl Sync for ConversionResult","synthetic":true,"types":["uucore::ConversionResult"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/marker/trait.Unpin.js b/implementors/core/marker/trait.Unpin.js new file mode 100644 index 000000000..77e374a60 --- /dev/null +++ b/implementors/core/marker/trait.Unpin.js @@ -0,0 +1,18 @@ +(function() {var implementors = {}; +implementors["uu_base32"] = [{"text":"impl Unpin for Config","synthetic":true,"types":["uu_base32::base_common::Config"]}]; +implementors["uu_cp"] = [{"text":"impl Unpin for Error","synthetic":true,"types":["uu_cp::Error"]},{"text":"impl Unpin for ClobberMode","synthetic":true,"types":["uu_cp::ClobberMode"]},{"text":"impl Unpin for OverwriteMode","synthetic":true,"types":["uu_cp::OverwriteMode"]},{"text":"impl Unpin for ReflinkMode","synthetic":true,"types":["uu_cp::ReflinkMode"]},{"text":"impl Unpin for TargetType","synthetic":true,"types":["uu_cp::TargetType"]},{"text":"impl Unpin for CopyMode","synthetic":true,"types":["uu_cp::CopyMode"]},{"text":"impl Unpin for Attribute","synthetic":true,"types":["uu_cp::Attribute"]},{"text":"impl Unpin for Options","synthetic":true,"types":["uu_cp::Options"]}]; +implementors["uu_csplit"] = [{"text":"impl Unpin for CsplitOptions","synthetic":true,"types":["uu_csplit::CsplitOptions"]}]; +implementors["uu_dircolors"] = [{"text":"impl Unpin for OutputFmt","synthetic":true,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl Unpin for Factors","synthetic":true,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_fmt"] = [{"text":"impl Unpin for FmtOptions","synthetic":true,"types":["uu_fmt::FmtOptions"]}]; +implementors["uu_install"] = [{"text":"impl Unpin for Behavior","synthetic":true,"types":["uu_install::Behavior"]},{"text":"impl Unpin for MainFunction","synthetic":true,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl Unpin for Mode","synthetic":true,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl Unpin for Settings","synthetic":true,"types":["uu_ln::Settings"]},{"text":"impl Unpin for OverwriteMode","synthetic":true,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl Unpin for Behavior","synthetic":true,"types":["uu_mv::Behavior"]},{"text":"impl Unpin for OverwriteMode","synthetic":true,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_nl"] = [{"text":"impl Unpin for Settings","synthetic":true,"types":["uu_nl::Settings"]}]; +implementors["uu_numfmt"] = [{"text":"impl<'a> Unpin for WhitespaceSplitter<'a>","synthetic":true,"types":["uu_numfmt::format::WhitespaceSplitter"]},{"text":"impl Unpin for TransformOptions","synthetic":true,"types":["uu_numfmt::options::TransformOptions"]},{"text":"impl Unpin for NumfmtOptions","synthetic":true,"types":["uu_numfmt::options::NumfmtOptions"]},{"text":"impl Unpin for RoundMethod","synthetic":true,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl Unpin for Output","synthetic":true,"types":["uu_sort::Output"]},{"text":"impl Unpin for GlobalSettings","synthetic":true,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> Unpin for Line<'a>","synthetic":true,"types":["uu_sort::Line"]},{"text":"impl Unpin for GeneralF64ParseResult","synthetic":true,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl Unpin for OutputType","synthetic":true,"types":["uu_stat::OutputType"]},{"text":"impl Unpin for Token","synthetic":true,"types":["uu_stat::Token"]},{"text":"impl Unpin for Stater","synthetic":true,"types":["uu_stat::Stater"]}]; +implementors["uu_wc"] = [{"text":"impl Unpin for WcError","synthetic":true,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Unpin for DecodeError","synthetic":true,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Unpin for EncodeError","synthetic":true,"types":["uucore::features::encoding::EncodeError"]},{"text":"impl Unpin for Format","synthetic":true,"types":["uucore::features::encoding::Format"]},{"text":"impl<R> Unpin for Data<R> where
    R: Unpin
","synthetic":true,"types":["uucore::features::encoding::Data"]},{"text":"impl Unpin for MissingHandling","synthetic":true,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl Unpin for ResolveMode","synthetic":true,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl Unpin for MountInfo","synthetic":true,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl Unpin for FsUsage","synthetic":true,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl<T> Unpin for RingBuffer<T> where
    T: Unpin
","synthetic":true,"types":["uucore::features::ringbuffer::RingBuffer"]},{"text":"impl<T> Unpin for ZeroCopyWriter<T> where
    T: Unpin
","synthetic":true,"types":["uucore::features::zero_copy::ZeroCopyWriter"]},{"text":"impl Unpin for Passwd","synthetic":true,"types":["uucore::features::entries::Passwd"]},{"text":"impl Unpin for Group","synthetic":true,"types":["uucore::features::entries::Group"]},{"text":"impl Unpin for VerbosityLevel","synthetic":true,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl Unpin for Verbosity","synthetic":true,"types":["uucore::features::perms::Verbosity"]},{"text":"impl Unpin for IfFrom","synthetic":true,"types":["uucore::features::perms::IfFrom"]},{"text":"impl Unpin for ChownExecutor","synthetic":true,"types":["uucore::features::perms::ChownExecutor"]},{"text":"impl Unpin for ExitStatus","synthetic":true,"types":["uucore::features::process::ExitStatus"]},{"text":"impl Unpin for Utmpx","synthetic":true,"types":["uucore::features::utmpx::Utmpx"]},{"text":"impl Unpin for UtmpxIter","synthetic":true,"types":["uucore::features::utmpx::UtmpxIter"]},{"text":"impl Unpin for BackupMode","synthetic":true,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl<'a> Unpin for HelpText<'a>","synthetic":true,"types":["uucore::mods::coreopts::HelpText"]},{"text":"impl<'a> Unpin for CoreOptions<'a>","synthetic":true,"types":["uucore::mods::coreopts::CoreOptions"]},{"text":"impl Unpin for USimpleError","synthetic":true,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Unpin for UUsageError","synthetic":true,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Unpin for UIoError","synthetic":true,"types":["uucore::mods::error::UIoError"]},{"text":"impl Unpin for ExitCode","synthetic":true,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Unpin for Range","synthetic":true,"types":["uucore::mods::ranges::Range"]},{"text":"impl Unpin for ParseSizeError","synthetic":true,"types":["uucore::parser::parse_size::ParseSizeError"]},{"text":"impl Unpin for InvalidEncodingHandling","synthetic":true,"types":["uucore::InvalidEncodingHandling"]},{"text":"impl Unpin for ConversionResult","synthetic":true,"types":["uucore::ConversionResult"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/core/str/traits/trait.FromStr.js b/implementors/core/str/traits/trait.FromStr.js new file mode 100644 index 000000000..825e8f78e --- /dev/null +++ b/implementors/core/str/traits/trait.FromStr.js @@ -0,0 +1,4 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl FromStr for Attribute","synthetic":false,"types":["uu_cp::Attribute"]}]; +implementors["uucore"] = [{"text":"impl FromStr for Range","synthetic":false,"types":["uucore::mods::ranges::Range"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/std/error/trait.Error.js b/implementors/std/error/trait.Error.js new file mode 100644 index 000000000..9c1ad2bfd --- /dev/null +++ b/implementors/std/error/trait.Error.js @@ -0,0 +1,5 @@ +(function() {var implementors = {}; +implementors["uu_cp"] = [{"text":"impl Error for Error","synthetic":false,"types":["uu_cp::Error"]}]; +implementors["uu_wc"] = [{"text":"impl Error for WcError","synthetic":false,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl Error for DecodeError","synthetic":false,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl Error for USimpleError","synthetic":false,"types":["uucore::mods::error::USimpleError"]},{"text":"impl Error for UUsageError","synthetic":false,"types":["uucore::mods::error::UUsageError"]},{"text":"impl Error for UIoError","synthetic":false,"types":["uucore::mods::error::UIoError"]},{"text":"impl Error for ExitCode","synthetic":false,"types":["uucore::mods::error::ExitCode"]},{"text":"impl Error for ParseSizeError","synthetic":false,"types":["uucore::parser::parse_size::ParseSizeError"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/std/io/trait.Write.js b/implementors/std/io/trait.Write.js new file mode 100644 index 000000000..cab107f92 --- /dev/null +++ b/implementors/std/io/trait.Write.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = [{"text":"impl<T: Write + AsRawObject + Sized> Write for ZeroCopyWriter<T>","synthetic":false,"types":["uucore::features::zero_copy::ZeroCopyWriter"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/std/panic/trait.RefUnwindSafe.js b/implementors/std/panic/trait.RefUnwindSafe.js new file mode 100644 index 000000000..53ce53f72 --- /dev/null +++ b/implementors/std/panic/trait.RefUnwindSafe.js @@ -0,0 +1,18 @@ +(function() {var implementors = {}; +implementors["uu_base32"] = [{"text":"impl RefUnwindSafe for Config","synthetic":true,"types":["uu_base32::base_common::Config"]}]; +implementors["uu_cp"] = [{"text":"impl !RefUnwindSafe for Error","synthetic":true,"types":["uu_cp::Error"]},{"text":"impl RefUnwindSafe for ClobberMode","synthetic":true,"types":["uu_cp::ClobberMode"]},{"text":"impl RefUnwindSafe for OverwriteMode","synthetic":true,"types":["uu_cp::OverwriteMode"]},{"text":"impl RefUnwindSafe for ReflinkMode","synthetic":true,"types":["uu_cp::ReflinkMode"]},{"text":"impl RefUnwindSafe for TargetType","synthetic":true,"types":["uu_cp::TargetType"]},{"text":"impl RefUnwindSafe for CopyMode","synthetic":true,"types":["uu_cp::CopyMode"]},{"text":"impl RefUnwindSafe for Attribute","synthetic":true,"types":["uu_cp::Attribute"]},{"text":"impl RefUnwindSafe for Options","synthetic":true,"types":["uu_cp::Options"]}]; +implementors["uu_csplit"] = [{"text":"impl !RefUnwindSafe for CsplitOptions","synthetic":true,"types":["uu_csplit::CsplitOptions"]}]; +implementors["uu_dircolors"] = [{"text":"impl RefUnwindSafe for OutputFmt","synthetic":true,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl !RefUnwindSafe for Factors","synthetic":true,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_fmt"] = [{"text":"impl RefUnwindSafe for FmtOptions","synthetic":true,"types":["uu_fmt::FmtOptions"]}]; +implementors["uu_install"] = [{"text":"impl RefUnwindSafe for Behavior","synthetic":true,"types":["uu_install::Behavior"]},{"text":"impl RefUnwindSafe for MainFunction","synthetic":true,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl RefUnwindSafe for Mode","synthetic":true,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl RefUnwindSafe for Settings","synthetic":true,"types":["uu_ln::Settings"]},{"text":"impl RefUnwindSafe for OverwriteMode","synthetic":true,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl RefUnwindSafe for Behavior","synthetic":true,"types":["uu_mv::Behavior"]},{"text":"impl RefUnwindSafe for OverwriteMode","synthetic":true,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_nl"] = [{"text":"impl RefUnwindSafe for Settings","synthetic":true,"types":["uu_nl::Settings"]}]; +implementors["uu_numfmt"] = [{"text":"impl<'a> RefUnwindSafe for WhitespaceSplitter<'a>","synthetic":true,"types":["uu_numfmt::format::WhitespaceSplitter"]},{"text":"impl RefUnwindSafe for TransformOptions","synthetic":true,"types":["uu_numfmt::options::TransformOptions"]},{"text":"impl RefUnwindSafe for NumfmtOptions","synthetic":true,"types":["uu_numfmt::options::NumfmtOptions"]},{"text":"impl RefUnwindSafe for RoundMethod","synthetic":true,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl RefUnwindSafe for Output","synthetic":true,"types":["uu_sort::Output"]},{"text":"impl RefUnwindSafe for GlobalSettings","synthetic":true,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> RefUnwindSafe for Line<'a>","synthetic":true,"types":["uu_sort::Line"]},{"text":"impl RefUnwindSafe for GeneralF64ParseResult","synthetic":true,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl RefUnwindSafe for OutputType","synthetic":true,"types":["uu_stat::OutputType"]},{"text":"impl RefUnwindSafe for Token","synthetic":true,"types":["uu_stat::Token"]},{"text":"impl RefUnwindSafe for Stater","synthetic":true,"types":["uu_stat::Stater"]}]; +implementors["uu_wc"] = [{"text":"impl !RefUnwindSafe for WcError","synthetic":true,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl !RefUnwindSafe for DecodeError","synthetic":true,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl RefUnwindSafe for EncodeError","synthetic":true,"types":["uucore::features::encoding::EncodeError"]},{"text":"impl RefUnwindSafe for Format","synthetic":true,"types":["uucore::features::encoding::Format"]},{"text":"impl<R> RefUnwindSafe for Data<R> where
    R: RefUnwindSafe
","synthetic":true,"types":["uucore::features::encoding::Data"]},{"text":"impl RefUnwindSafe for MissingHandling","synthetic":true,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl RefUnwindSafe for ResolveMode","synthetic":true,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl RefUnwindSafe for MountInfo","synthetic":true,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl RefUnwindSafe for FsUsage","synthetic":true,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl<T> RefUnwindSafe for RingBuffer<T> where
    T: RefUnwindSafe
","synthetic":true,"types":["uucore::features::ringbuffer::RingBuffer"]},{"text":"impl<T> RefUnwindSafe for ZeroCopyWriter<T> where
    T: RefUnwindSafe
","synthetic":true,"types":["uucore::features::zero_copy::ZeroCopyWriter"]},{"text":"impl RefUnwindSafe for Passwd","synthetic":true,"types":["uucore::features::entries::Passwd"]},{"text":"impl RefUnwindSafe for Group","synthetic":true,"types":["uucore::features::entries::Group"]},{"text":"impl RefUnwindSafe for VerbosityLevel","synthetic":true,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl RefUnwindSafe for Verbosity","synthetic":true,"types":["uucore::features::perms::Verbosity"]},{"text":"impl RefUnwindSafe for IfFrom","synthetic":true,"types":["uucore::features::perms::IfFrom"]},{"text":"impl RefUnwindSafe for ChownExecutor","synthetic":true,"types":["uucore::features::perms::ChownExecutor"]},{"text":"impl RefUnwindSafe for ExitStatus","synthetic":true,"types":["uucore::features::process::ExitStatus"]},{"text":"impl RefUnwindSafe for Utmpx","synthetic":true,"types":["uucore::features::utmpx::Utmpx"]},{"text":"impl RefUnwindSafe for UtmpxIter","synthetic":true,"types":["uucore::features::utmpx::UtmpxIter"]},{"text":"impl RefUnwindSafe for BackupMode","synthetic":true,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl<'a> RefUnwindSafe for HelpText<'a>","synthetic":true,"types":["uucore::mods::coreopts::HelpText"]},{"text":"impl<'a> RefUnwindSafe for CoreOptions<'a>","synthetic":true,"types":["uucore::mods::coreopts::CoreOptions"]},{"text":"impl RefUnwindSafe for USimpleError","synthetic":true,"types":["uucore::mods::error::USimpleError"]},{"text":"impl RefUnwindSafe for UUsageError","synthetic":true,"types":["uucore::mods::error::UUsageError"]},{"text":"impl !RefUnwindSafe for UIoError","synthetic":true,"types":["uucore::mods::error::UIoError"]},{"text":"impl RefUnwindSafe for ExitCode","synthetic":true,"types":["uucore::mods::error::ExitCode"]},{"text":"impl RefUnwindSafe for Range","synthetic":true,"types":["uucore::mods::ranges::Range"]},{"text":"impl RefUnwindSafe for ParseSizeError","synthetic":true,"types":["uucore::parser::parse_size::ParseSizeError"]},{"text":"impl RefUnwindSafe for InvalidEncodingHandling","synthetic":true,"types":["uucore::InvalidEncodingHandling"]},{"text":"impl RefUnwindSafe for ConversionResult","synthetic":true,"types":["uucore::ConversionResult"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/std/panic/trait.UnwindSafe.js b/implementors/std/panic/trait.UnwindSafe.js new file mode 100644 index 000000000..e334d477f --- /dev/null +++ b/implementors/std/panic/trait.UnwindSafe.js @@ -0,0 +1,18 @@ +(function() {var implementors = {}; +implementors["uu_base32"] = [{"text":"impl UnwindSafe for Config","synthetic":true,"types":["uu_base32::base_common::Config"]}]; +implementors["uu_cp"] = [{"text":"impl !UnwindSafe for Error","synthetic":true,"types":["uu_cp::Error"]},{"text":"impl UnwindSafe for ClobberMode","synthetic":true,"types":["uu_cp::ClobberMode"]},{"text":"impl UnwindSafe for OverwriteMode","synthetic":true,"types":["uu_cp::OverwriteMode"]},{"text":"impl UnwindSafe for ReflinkMode","synthetic":true,"types":["uu_cp::ReflinkMode"]},{"text":"impl UnwindSafe for TargetType","synthetic":true,"types":["uu_cp::TargetType"]},{"text":"impl UnwindSafe for CopyMode","synthetic":true,"types":["uu_cp::CopyMode"]},{"text":"impl UnwindSafe for Attribute","synthetic":true,"types":["uu_cp::Attribute"]},{"text":"impl UnwindSafe for Options","synthetic":true,"types":["uu_cp::Options"]}]; +implementors["uu_csplit"] = [{"text":"impl !UnwindSafe for CsplitOptions","synthetic":true,"types":["uu_csplit::CsplitOptions"]}]; +implementors["uu_dircolors"] = [{"text":"impl UnwindSafe for OutputFmt","synthetic":true,"types":["uu_dircolors::OutputFmt"]}]; +implementors["uu_factor"] = [{"text":"impl UnwindSafe for Factors","synthetic":true,"types":["uu_factor::factor::Factors"]}]; +implementors["uu_fmt"] = [{"text":"impl UnwindSafe for FmtOptions","synthetic":true,"types":["uu_fmt::FmtOptions"]}]; +implementors["uu_install"] = [{"text":"impl UnwindSafe for Behavior","synthetic":true,"types":["uu_install::Behavior"]},{"text":"impl UnwindSafe for MainFunction","synthetic":true,"types":["uu_install::MainFunction"]}]; +implementors["uu_kill"] = [{"text":"impl UnwindSafe for Mode","synthetic":true,"types":["uu_kill::Mode"]}]; +implementors["uu_ln"] = [{"text":"impl UnwindSafe for Settings","synthetic":true,"types":["uu_ln::Settings"]},{"text":"impl UnwindSafe for OverwriteMode","synthetic":true,"types":["uu_ln::OverwriteMode"]}]; +implementors["uu_mv"] = [{"text":"impl UnwindSafe for Behavior","synthetic":true,"types":["uu_mv::Behavior"]},{"text":"impl UnwindSafe for OverwriteMode","synthetic":true,"types":["uu_mv::OverwriteMode"]}]; +implementors["uu_nl"] = [{"text":"impl UnwindSafe for Settings","synthetic":true,"types":["uu_nl::Settings"]}]; +implementors["uu_numfmt"] = [{"text":"impl<'a> UnwindSafe for WhitespaceSplitter<'a>","synthetic":true,"types":["uu_numfmt::format::WhitespaceSplitter"]},{"text":"impl UnwindSafe for TransformOptions","synthetic":true,"types":["uu_numfmt::options::TransformOptions"]},{"text":"impl UnwindSafe for NumfmtOptions","synthetic":true,"types":["uu_numfmt::options::NumfmtOptions"]},{"text":"impl UnwindSafe for RoundMethod","synthetic":true,"types":["uu_numfmt::options::RoundMethod"]}]; +implementors["uu_sort"] = [{"text":"impl UnwindSafe for Output","synthetic":true,"types":["uu_sort::Output"]},{"text":"impl UnwindSafe for GlobalSettings","synthetic":true,"types":["uu_sort::GlobalSettings"]},{"text":"impl<'a> UnwindSafe for Line<'a>","synthetic":true,"types":["uu_sort::Line"]},{"text":"impl UnwindSafe for GeneralF64ParseResult","synthetic":true,"types":["uu_sort::GeneralF64ParseResult"]}]; +implementors["uu_stat"] = [{"text":"impl UnwindSafe for OutputType","synthetic":true,"types":["uu_stat::OutputType"]},{"text":"impl UnwindSafe for Token","synthetic":true,"types":["uu_stat::Token"]},{"text":"impl UnwindSafe for Stater","synthetic":true,"types":["uu_stat::Stater"]}]; +implementors["uu_wc"] = [{"text":"impl !UnwindSafe for WcError","synthetic":true,"types":["uu_wc::WcError"]}]; +implementors["uucore"] = [{"text":"impl !UnwindSafe for DecodeError","synthetic":true,"types":["uucore::features::encoding::DecodeError"]},{"text":"impl UnwindSafe for EncodeError","synthetic":true,"types":["uucore::features::encoding::EncodeError"]},{"text":"impl UnwindSafe for Format","synthetic":true,"types":["uucore::features::encoding::Format"]},{"text":"impl<R> UnwindSafe for Data<R> where
    R: UnwindSafe
","synthetic":true,"types":["uucore::features::encoding::Data"]},{"text":"impl UnwindSafe for MissingHandling","synthetic":true,"types":["uucore::features::fs::MissingHandling"]},{"text":"impl UnwindSafe for ResolveMode","synthetic":true,"types":["uucore::features::fs::ResolveMode"]},{"text":"impl UnwindSafe for MountInfo","synthetic":true,"types":["uucore::features::fsext::MountInfo"]},{"text":"impl UnwindSafe for FsUsage","synthetic":true,"types":["uucore::features::fsext::FsUsage"]},{"text":"impl<T> UnwindSafe for RingBuffer<T> where
    T: UnwindSafe
","synthetic":true,"types":["uucore::features::ringbuffer::RingBuffer"]},{"text":"impl<T> UnwindSafe for ZeroCopyWriter<T> where
    T: UnwindSafe
","synthetic":true,"types":["uucore::features::zero_copy::ZeroCopyWriter"]},{"text":"impl UnwindSafe for Passwd","synthetic":true,"types":["uucore::features::entries::Passwd"]},{"text":"impl UnwindSafe for Group","synthetic":true,"types":["uucore::features::entries::Group"]},{"text":"impl UnwindSafe for VerbosityLevel","synthetic":true,"types":["uucore::features::perms::VerbosityLevel"]},{"text":"impl UnwindSafe for Verbosity","synthetic":true,"types":["uucore::features::perms::Verbosity"]},{"text":"impl UnwindSafe for IfFrom","synthetic":true,"types":["uucore::features::perms::IfFrom"]},{"text":"impl UnwindSafe for ChownExecutor","synthetic":true,"types":["uucore::features::perms::ChownExecutor"]},{"text":"impl UnwindSafe for ExitStatus","synthetic":true,"types":["uucore::features::process::ExitStatus"]},{"text":"impl UnwindSafe for Utmpx","synthetic":true,"types":["uucore::features::utmpx::Utmpx"]},{"text":"impl UnwindSafe for UtmpxIter","synthetic":true,"types":["uucore::features::utmpx::UtmpxIter"]},{"text":"impl UnwindSafe for BackupMode","synthetic":true,"types":["uucore::mods::backup_control::BackupMode"]},{"text":"impl<'a> UnwindSafe for HelpText<'a>","synthetic":true,"types":["uucore::mods::coreopts::HelpText"]},{"text":"impl<'a> UnwindSafe for CoreOptions<'a>","synthetic":true,"types":["uucore::mods::coreopts::CoreOptions"]},{"text":"impl UnwindSafe for USimpleError","synthetic":true,"types":["uucore::mods::error::USimpleError"]},{"text":"impl UnwindSafe for UUsageError","synthetic":true,"types":["uucore::mods::error::UUsageError"]},{"text":"impl !UnwindSafe for UIoError","synthetic":true,"types":["uucore::mods::error::UIoError"]},{"text":"impl UnwindSafe for ExitCode","synthetic":true,"types":["uucore::mods::error::ExitCode"]},{"text":"impl UnwindSafe for Range","synthetic":true,"types":["uucore::mods::ranges::Range"]},{"text":"impl UnwindSafe for ParseSizeError","synthetic":true,"types":["uucore::parser::parse_size::ParseSizeError"]},{"text":"impl UnwindSafe for InvalidEncodingHandling","synthetic":true,"types":["uucore::InvalidEncodingHandling"]},{"text":"impl UnwindSafe for ConversionResult","synthetic":true,"types":["uucore::ConversionResult"]}]; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uu_chgrp/entries/trait.Locate.js b/implementors/uu_chgrp/entries/trait.Locate.js new file mode 100644 index 000000000..1ff9d8ac1 --- /dev/null +++ b/implementors/uu_chgrp/entries/trait.Locate.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uu_chgrp"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uu_chown/trait.Locate.js b/implementors/uu_chown/trait.Locate.js new file mode 100644 index 000000000..4b13757bc --- /dev/null +++ b/implementors/uu_chown/trait.Locate.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uu_chown"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uu_dircolors/trait.StrUtils.js b/implementors/uu_dircolors/trait.StrUtils.js new file mode 100644 index 000000000..3212f81f6 --- /dev/null +++ b/implementors/uu_dircolors/trait.StrUtils.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uu_dircolors"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uu_pinky/trait.Capitalize.js b/implementors/uu_pinky/trait.Capitalize.js new file mode 100644 index 000000000..5716a7f4b --- /dev/null +++ b/implementors/uu_pinky/trait.Capitalize.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uu_pinky"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uu_stat/trait.ScanUtil.js b/implementors/uu_stat/trait.ScanUtil.js new file mode 100644 index 000000000..ebdd4368b --- /dev/null +++ b/implementors/uu_stat/trait.ScanUtil.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uu_stat"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/entries/trait.Locate.js b/implementors/uucore/entries/trait.Locate.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/entries/trait.Locate.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/error/trait.FromIo.js b/implementors/uucore/error/trait.FromIo.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/error/trait.FromIo.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/error/trait.UError.js b/implementors/uucore/error/trait.UError.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/error/trait.UError.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/fsext/trait.BirthTime.js b/implementors/uucore/fsext/trait.BirthTime.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/fsext/trait.BirthTime.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/fsext/trait.FsMeta.js b/implementors/uucore/fsext/trait.FsMeta.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/fsext/trait.FsMeta.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/process/trait.ChildExt.js b/implementors/uucore/process/trait.ChildExt.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/process/trait.ChildExt.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/trait.Args.js b/implementors/uucore/trait.Args.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/trait.Args.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/zero_copy/trait.AsRawObject.js b/implementors/uucore/zero_copy/trait.AsRawObject.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/zero_copy/trait.AsRawObject.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/implementors/uucore/zero_copy/trait.FromRawObject.js b/implementors/uucore/zero_copy/trait.FromRawObject.js new file mode 100644 index 000000000..d853d3b38 --- /dev/null +++ b/implementors/uucore/zero_copy/trait.FromRawObject.js @@ -0,0 +1,3 @@ +(function() {var implementors = {}; +implementors["uucore"] = []; +if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/install/all.html b/install/all.html new file mode 100644 index 000000000..a4f0fe17d --- /dev/null +++ b/install/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/install/fn.main.html b/install/fn.main.html new file mode 100644 index 000000000..9d5561ac6 --- /dev/null +++ b/install/fn.main.html @@ -0,0 +1,3 @@ +main in install - Rust + +

Function install::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/install/index.html b/install/index.html new file mode 100644 index 000000000..56e25fcda --- /dev/null +++ b/install/index.html @@ -0,0 +1,4 @@ +install - Rust + +

Crate install[][src]

Functions

+
main
\ No newline at end of file diff --git a/install/sidebar-items.js b/install/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/install/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/join/all.html b/join/all.html new file mode 100644 index 000000000..ca9d37a08 --- /dev/null +++ b/join/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/join/fn.main.html b/join/fn.main.html new file mode 100644 index 000000000..e02c08d6d --- /dev/null +++ b/join/fn.main.html @@ -0,0 +1,3 @@ +main in join - Rust + +

Function join::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/join/index.html b/join/index.html new file mode 100644 index 000000000..2cbd15256 --- /dev/null +++ b/join/index.html @@ -0,0 +1,4 @@ +join - Rust + +

Crate join[][src]

Functions

+
main
\ No newline at end of file diff --git a/join/sidebar-items.js b/join/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/join/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/kill/all.html b/kill/all.html new file mode 100644 index 000000000..ad308dd1f --- /dev/null +++ b/kill/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/kill/fn.main.html b/kill/fn.main.html new file mode 100644 index 000000000..608fffeea --- /dev/null +++ b/kill/fn.main.html @@ -0,0 +1,3 @@ +main in kill - Rust + +

Function kill::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/kill/index.html b/kill/index.html new file mode 100644 index 000000000..be9386d48 --- /dev/null +++ b/kill/index.html @@ -0,0 +1,4 @@ +kill - Rust + +

Crate kill[][src]

Functions

+
main
\ No newline at end of file diff --git a/kill/sidebar-items.js b/kill/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/kill/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/libstdbuf/all.html b/libstdbuf/all.html new file mode 100644 index 000000000..88a0155ad --- /dev/null +++ b/libstdbuf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/libstdbuf/fn.__stdbuf.html b/libstdbuf/fn.__stdbuf.html new file mode 100644 index 000000000..78db20ab1 --- /dev/null +++ b/libstdbuf/fn.__stdbuf.html @@ -0,0 +1,6 @@ +__stdbuf in libstdbuf - Rust + +

Function libstdbuf::__stdbuf[][src]

#[no_mangle]
+pub unsafe extern "C" fn __stdbuf()
Expand description

Safety

+

ToDO … (safety note)

+
\ No newline at end of file diff --git a/libstdbuf/index.html b/libstdbuf/index.html new file mode 100644 index 000000000..975381592 --- /dev/null +++ b/libstdbuf/index.html @@ -0,0 +1,5 @@ +libstdbuf - Rust + +

Crate libstdbuf[][src]

Functions

+
__stdbuf

Safety

+
\ No newline at end of file diff --git a/libstdbuf/sidebar-items.js b/libstdbuf/sidebar-items.js new file mode 100644 index 000000000..287661451 --- /dev/null +++ b/libstdbuf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["__stdbuf","Safety"]]}); \ No newline at end of file diff --git a/light.css b/light.css new file mode 100644 index 000000000..a5aa6d036 --- /dev/null +++ b/light.css @@ -0,0 +1 @@ + body{background-color:white;color:black;}h1,h2,h3,h4{color:black;}h1.fqn{border-bottom-color:#D5D5D5;}h2,h3,h4{border-bottom-color:#DDDDDD;}.in-band{background-color:white;}.invisible{background:rgba(0,0,0,0);}.docblock code,.docblock-short code{background-color:#F5F5F5;}pre,.rustdoc.source .example-wrap{background-color:#F5F5F5;}.sidebar{background-color:#F1F1F1;}*{scrollbar-color:rgba(36,37,39,0.6) #e6e6e6;}.sidebar{scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;}.logo-container.rust-logo>img{}::-webkit-scrollbar-track{background-color:#ecebeb;}::-webkit-scrollbar-thumb{background-color:rgba(36,37,39,0.6);}.sidebar::-webkit-scrollbar-track{background-color:#dcdcdc;}.sidebar::-webkit-scrollbar-thumb{background-color:rgba(36,37,39,0.6);}.sidebar .current{background-color:#fff;}.source .sidebar{background-color:#fff;}.sidebar .location{border-color:#000;background-color:#fff;color:#333;}.sidebar .version{border-bottom-color:#DDD;}.sidebar-title{border-top-color:#777;border-bottom-color:#777;}.block a:hover{background:#F5F5F5;}.line-numbers span{color:#c67e2d;}.line-numbers .line-highlighted{background-color:#f6fdb0 !important;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom-color:#ddd;}.docblock table,.docblock table td,.docblock table th{border-color:#ddd;}.content .method .where,.content .fn .where,.content .where.fmt-newline{color:#4E4C4C;}.search-results a:hover{background-color:#ddd;}.search-results a:focus{color:#000 !important;background-color:#ccc;}.search-results a:focus span{color:#000 !important;}a.result-trait:focus{background-color:#c7b6ff;}a.result-traitalias:focus{background-color:#c7b6ff;}a.result-mod:focus,a.result-externcrate:focus{background-color:#afc6e4;}a.result-enum:focus{background-color:#b4d1b9;}a.result-struct:focus{background-color:#e7b1a0;}a.result-union:focus{background-color:#b7bd49;}a.result-fn:focus,a.result-method:focus,a.result-tymethod:focus{background-color:#c6afb3;}a.result-type:focus{background-color:#ffc891;}a.result-foreigntype:focus{background-color:#f5c4ff;}a.result-attr:focus,a.result-derive:focus,a.result-macro:focus{background-color:#8ce488;}a.result-constant:focus,a.result-static:focus{background-color:#c3e0ff;}a.result-primitive:focus{background-color:#9aecff;}a.result-keyword:focus{background-color:#f99650;}.content .item-info::before{color:#ccc;}.content span.enum,.content a.enum,.block a.current.enum{color:#508157;}.content span.struct,.content a.struct,.block a.current.struct{color:#ad448e;}.content span.type,.content a.type,.block a.current.type{color:#ba5d00;}.content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype{color:#cd00e2;}.content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive,.block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro{color:#068000;}.content span.union,.content a.union,.block a.current.union{color:#767b27;}.content span.constant,.content a.constant,.block a.current.constant,.content span.static,.content a.static,.block a.current.static{color:#546e8a;}.content span.primitive,.content a.primitive,.block a.current.primitive{color:#2c8093;}.content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod{color:#4d76ae;}.content span.trait,.content a.trait,.block a.current.trait{color:#7c5af3;}.content span.traitalias,.content a.traitalias,.block a.current.traitalias{color:#6841f1;}.content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method,.block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod,.content .fnname{color:#9a6e31;}.content span.keyword,.content a.keyword,.block a.current.keyword{color:#de5249;}pre.rust .comment{color:#8E908C;}pre.rust .doccomment{color:#4D4D4C;}nav:not(.sidebar){border-bottom-color:#e0e0e0;}nav.main .current{border-top-color:#000;border-bottom-color:#000;}nav.main .separator{border:1px solid #000;}a{color:#000;}.docblock:not(.type-decl) a:not(.srclink):not(.test-arrow),.docblock-short a:not(.srclink):not(.test-arrow),.item-info a,#help a{color:#3873AD;}a.test-arrow{color:#f5f5f5;}details.rustdoc-toggle>summary.hideme>span,details.rustdoc-toggle>summary::before,details.undocumented>summary::before{color:#999;}#crate-search{color:#555;background-color:white;border-color:#e0e0e0;box-shadow:0 0 0 1px #e0e0e0,0 0 0 2px transparent;}.search-input{color:#555;background-color:white;box-shadow:0 0 0 1px #e0e0e0,0 0 0 2px transparent;}.search-input:focus{border-color:#66afe9;}.search-input:disabled{background-color:#e6e6e6;}#crate-search+.search-input:focus{box-shadow:0 0 8px #078dd8;}.module-item .stab,.import-item .stab{color:#000;}.stab.unstable{background:#FFF5D6;border-color:#FFC600;}.stab.deprecated{background:#ffc4c4;border-color:#db7b7b;}.stab.portability{background:#F3DFFF;border-color:#b07bdb;}.stab.portability>code{background:none;}#help>div{background:#e9e9e9;border-color:#bfbfbf;}#help>div>span{border-bottom-color:#bfbfbf;}.since{color:grey;}tr.result span.primitive::after,tr.result span.keyword::after{color:black;}.line-numbers :target{background-color:transparent;}pre.rust .kw{color:#8959A8;}pre.rust .kw-2,pre.rust .prelude-ty{color:#4271AE;}pre.rust .number,pre.rust .string{color:#718C00;}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute,pre.rust .attribute .ident{color:#C82829;}pre.rust .macro,pre.rust .macro-nonterminal{color:#3E999F;}pre.rust .lifetime{color:#B76514;}pre.rust .question-mark{color:#ff9011;}.example-wrap>pre.line-number{border-color:#c7c7c7;}a.test-arrow{background-color:rgba(78,139,202,0.2);}a.test-arrow:hover{background-color:#4e8bca;}.toggle-label,.code-attribute{color:#999;}:target,:target>*{background:#FDFFD3;}pre.compile_fail{border-left:2px solid rgba(255,0,0,.5);}pre.compile_fail:hover,.information:hover+pre.compile_fail{border-left:2px solid #f00;}pre.should_panic{border-left:2px solid rgba(255,0,0,.5);}pre.should_panic:hover,.information:hover+pre.should_panic{border-left:2px solid #f00;}pre.ignore{border-left:2px solid rgba(255,142,0,.6);}pre.ignore:hover,.information:hover+pre.ignore{border-left:2px solid #ff9200;}.tooltip.compile_fail{color:rgba(255,0,0,.5);}.information>.compile_fail:hover{color:#f00;}.tooltip.should_panic{color:rgba(255,0,0,.5);}.information>.should_panic:hover{color:#f00;}.tooltip.ignore{color:rgba(255,142,0,.6);}.information>.ignore:hover{color:#ff9200;}.search-failed a{color:#0089ff;}.tooltip::after{background-color:#000;color:#fff;}.tooltip::before{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#eee;border-color:#999;}.notable-traits-tooltiptext .notable{border-bottom-color:#DDDDDD;}#titles>button:not(.selected){background-color:#e6e6e6;border-top-color:#e6e6e6;}#titles>button:hover,#titles>button.selected{background-color:#ffffff;border-top-color:#0089ff;}#titles>button>div.count{color:#888;}@media (max-width:700px){.sidebar-menu{background-color:#F1F1F1;border-bottom-color:#e0e0e0;border-right-color:#e0e0e0;}.sidebar-elems{background-color:#F1F1F1;border-right-color:#000;}#sidebar-filler{background-color:#F1F1F1;border-bottom-color:#e0e0e0;}}kbd{color:#000;background-color:#fafbfc;border-color:#d1d5da;border-bottom-color:#c6cbd1;box-shadow-color:#c6cbd1;}#theme-picker,#settings-menu,#help-button{border-color:#e0e0e0;background-color:#fff;}#theme-picker:hover,#theme-picker:focus,#settings-menu:hover,#settings-menu:focus,#help-button:hover,#help-button:focus{border-color:#717171;}#copy-path{color:#999;}#copy-path>img{filter:invert(50%);}#copy-path:hover>img{filter:invert(35%);}#theme-choices{border-color:#ccc;background-color:#fff;}#theme-choices>button:not(:first-child){border-top-color:#e0e0e0;}#theme-choices>button:hover,#theme-choices>button:focus{background-color:#eee;}@media (max-width:700px){#theme-picker{background:#fff;}}#all-types{background-color:#fff;}#all-types:hover{background-color:#f9f9f9;}.search-results .result-name span.alias{color:#000;}.search-results .result-name span.grey{color:#999;}#sidebar-toggle{background-color:#F1F1F1;}#sidebar-toggle:hover{background-color:#E0E0E0;}#source-sidebar{background-color:#F1F1F1;}#source-sidebar>.title{border-bottom-color:#ccc;}div.files>a:hover,div.name:hover{background-color:#E0E0E0;}div.files>.selected{background-color:#fff;}.setting-line>.title{border-bottom-color:#D5D5D5;} \ No newline at end of file diff --git a/link/all.html b/link/all.html new file mode 100644 index 000000000..76dc79043 --- /dev/null +++ b/link/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/link/fn.main.html b/link/fn.main.html new file mode 100644 index 000000000..0a085b6ca --- /dev/null +++ b/link/fn.main.html @@ -0,0 +1,3 @@ +main in link - Rust + +

Function link::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/link/index.html b/link/index.html new file mode 100644 index 000000000..9521d9000 --- /dev/null +++ b/link/index.html @@ -0,0 +1,4 @@ +link - Rust + +

Crate link[][src]

Functions

+
main
\ No newline at end of file diff --git a/link/sidebar-items.js b/link/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/link/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/ln/all.html b/ln/all.html new file mode 100644 index 000000000..5f8a1bcc6 --- /dev/null +++ b/ln/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/ln/fn.main.html b/ln/fn.main.html new file mode 100644 index 000000000..af3e77e2f --- /dev/null +++ b/ln/fn.main.html @@ -0,0 +1,3 @@ +main in ln - Rust + +

Function ln::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/ln/index.html b/ln/index.html new file mode 100644 index 000000000..c2d0fc705 --- /dev/null +++ b/ln/index.html @@ -0,0 +1,4 @@ +ln - Rust + +

Crate ln[][src]

Functions

+
main
\ No newline at end of file diff --git a/ln/sidebar-items.js b/ln/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/ln/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/logname/all.html b/logname/all.html new file mode 100644 index 000000000..37a8c6ca8 --- /dev/null +++ b/logname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/logname/fn.main.html b/logname/fn.main.html new file mode 100644 index 000000000..a3bd71c00 --- /dev/null +++ b/logname/fn.main.html @@ -0,0 +1,3 @@ +main in logname - Rust + +

Function logname::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/logname/index.html b/logname/index.html new file mode 100644 index 000000000..00b0c4abc --- /dev/null +++ b/logname/index.html @@ -0,0 +1,4 @@ +logname - Rust + +

Crate logname[][src]

Functions

+
main
\ No newline at end of file diff --git a/logname/sidebar-items.js b/logname/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/logname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/ls/all.html b/ls/all.html new file mode 100644 index 000000000..cdb846263 --- /dev/null +++ b/ls/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/ls/fn.main.html b/ls/fn.main.html new file mode 100644 index 000000000..a79b5f5ef --- /dev/null +++ b/ls/fn.main.html @@ -0,0 +1,3 @@ +main in ls - Rust + +

Function ls::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/ls/index.html b/ls/index.html new file mode 100644 index 000000000..8c5eb9ad3 --- /dev/null +++ b/ls/index.html @@ -0,0 +1,4 @@ +ls - Rust + +

Crate ls[][src]

Functions

+
main
\ No newline at end of file diff --git a/ls/sidebar-items.js b/ls/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/ls/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/main.js b/main.js new file mode 100644 index 000000000..a4d3fe44d --- /dev/null +++ b/main.js @@ -0,0 +1,8 @@ +if(!String.prototype.startsWith){String.prototype.startsWith=function(searchString,position){position=position||0;return this.indexOf(searchString,position)===position}}if(!String.prototype.endsWith){String.prototype.endsWith=function(suffix,length){var l=length||this.length;return this.indexOf(suffix,l-suffix.length)!==-1}}if(!DOMTokenList.prototype.add){DOMTokenList.prototype.add=function(className){if(className&&!hasClass(this,className)){if(this.className&&this.className.length>0){this.className+=" "+className}else{this.className=className}}}}if(!DOMTokenList.prototype.remove){DOMTokenList.prototype.remove=function(className){if(className&&this.className){this.className=(" "+this.className+" ").replace(" "+className+" "," ").trim()}}}(function(){var rustdocVars=document.getElementById("rustdoc-vars");if(rustdocVars){window.rootPath=rustdocVars.attributes["data-root-path"].value;window.currentCrate=rustdocVars.attributes["data-current-crate"].value;window.searchJS=rustdocVars.attributes["data-search-js"].value;window.searchIndexJS=rustdocVars.attributes["data-search-index-js"].value}var sidebarVars=document.getElementById("sidebar-vars");if(sidebarVars){window.sidebarCurrent={name:sidebarVars.attributes["data-name"].value,ty:sidebarVars.attributes["data-ty"].value,relpath:sidebarVars.attributes["data-relpath"].value,}}}());function getVirtualKey(ev){if("key"in ev&&typeof ev.key!="undefined"){return ev.key}var c=ev.charCode||ev.keyCode;if(c==27){return"Escape"}return String.fromCharCode(c)}var THEME_PICKER_ELEMENT_ID="theme-picker";var THEMES_ELEMENT_ID="theme-choices";function getThemesElement(){return document.getElementById(THEMES_ELEMENT_ID)}function getThemePickerElement(){return document.getElementById(THEME_PICKER_ELEMENT_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function showThemeButtonState(){var themePicker=getThemePickerElement();var themeChoices=getThemesElement();themeChoices.style.display="block";themePicker.style.borderBottomRightRadius="0";themePicker.style.borderBottomLeftRadius="0"}function hideThemeButtonState(){var themePicker=getThemePickerElement();var themeChoices=getThemesElement();themeChoices.style.display="none";themePicker.style.borderBottomRightRadius="3px";themePicker.style.borderBottomLeftRadius="3px"}(function(){var themeChoices=getThemesElement();var themePicker=getThemePickerElement();var availableThemes=["ayu","dark","light"];function switchThemeButtonState(){if(themeChoices.style.display==="block"){hideThemeButtonState()}else{showThemeButtonState()}}function handleThemeButtonsBlur(e){var active=document.activeElement;var related=e.relatedTarget;if(active.id!==THEME_PICKER_ELEMENT_ID&&(!active.parentNode||active.parentNode.id!==THEMES_ELEMENT_ID)&&(!related||(related.id!==THEME_PICKER_ELEMENT_ID&&(!related.parentNode||related.parentNode.id!==THEMES_ELEMENT_ID)))){hideThemeButtonState()}}themePicker.onclick=switchThemeButtonState;themePicker.onblur=handleThemeButtonsBlur;availableThemes.forEach(function(item){var but=document.createElement("button");but.textContent=item;but.onclick=function(){switchTheme(window.currentTheme,window.mainTheme,item,true);useSystemTheme(false)};but.onblur=handleThemeButtonsBlur;themeChoices.appendChild(but)})}());(function(){"use strict";window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:function(){return document.getElementById("search")},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:function(){if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},focus:function(){searchState.input.focus()},defocus:function(){searchState.input.blur()},showResults:function(search){if(search===null||typeof search==='undefined'){search=searchState.outputElement()}addClass(main,"hidden");removeClass(search,"hidden");searchState.mouseMovedAfterSearch=false;document.title=searchState.title},hideResults:function(search){if(search===null||typeof search==='undefined'){search=searchState.outputElement()}addClass(search,"hidden");removeClass(main,"hidden");document.title=searchState.titleBeforeSearch;if(searchState.browserSupportsHistoryApi()){history.replaceState("",window.currentCrate+" - Rust",getNakedUrl()+window.location.hash)}},getQueryStringParams:function(){var params={};window.location.search.substring(1).split("&").map(function(s){var pair=s.split("=");params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},putBackSearch:function(search_input){var search=searchState.outputElement();if(search_input.value!==""&&hasClass(search,"hidden")){searchState.showResults(search);if(searchState.browserSupportsHistoryApi()){var extra="?search="+encodeURIComponent(search_input.value);history.replaceState(search_input.value,"",getNakedUrl()+extra+window.location.hash)}document.title=searchState.title}},browserSupportsHistoryApi:function(){return window.history&&typeof window.history.pushState==="function"},setup:function(){var search_input=searchState.input;if(!searchState.input){return}function loadScript(url){var script=document.createElement('script');script.src=url;document.head.append(script)}var searchLoaded=false;function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(window.searchJS);loadScript(window.searchIndexJS)}}search_input.addEventListener("focus",function(){searchState.putBackSearch(this);search_input.origPlaceholder=searchState.input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});search_input.addEventListener("blur",function(){search_input.placeholder=searchState.input.origPlaceholder});search_input.removeAttribute('disabled');searchState.addCrateDropdown(window.ALL_CRATES);var params=searchState.getQueryStringParams();if(params.search!==undefined){var search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search);loadSearch()}},addCrateDropdown:function(crates){var elem=document.getElementById("crate-search");if(!elem){return}var savedCrate=getSettingValue("saved-filter-crate");for(var i=0,len=crates.length;i0){return tmp}}return null}function showSidebar(){var elems=document.getElementsByClassName("sidebar-elems")[0];if(elems){addClass(elems,"show-it")}var sidebar=document.getElementsByClassName("sidebar")[0];if(sidebar){addClass(sidebar,"mobile");var filler=document.getElementById("sidebar-filler");if(!filler){var div=document.createElement("div");div.id="sidebar-filler";sidebar.appendChild(div)}}}function hideSidebar(){var elems=document.getElementsByClassName("sidebar-elems")[0];if(elems){removeClass(elems,"show-it")}var sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"mobile");var filler=document.getElementById("sidebar-filler");if(filler){filler.remove()}document.getElementsByTagName("body")[0].style.marginTop=""}var toggleAllDocsId="toggle-all-docs";var main=document.getElementById("main");var savedHash="";function handleHashes(ev){var elem;var search=searchState.outputElement();if(ev!==null&&search&&!hasClass(search,"hidden")&&ev.newURL){searchState.hideResults(search);var hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(searchState.browserSupportsHistoryApi()){history.replaceState(hash,"",getNakedUrl()+window.location.search+"#"+hash)}elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}if(savedHash!==window.location.hash){savedHash=window.location.hash;if(savedHash.length===0){return}expandSection(savedHash.slice(1))}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function getHelpElement(build){if(build){buildHelperPopup()}return document.getElementById("help")}function displayHelp(display,ev,help){if(display){help=help?help:getHelpElement(true);if(hasClass(help,"hidden")){ev.preventDefault();removeClass(help,"hidden");addClass(document.body,"blur")}}else{help=help?help:getHelpElement(false);if(help&&!hasClass(help,"hidden")){ev.preventDefault();addClass(help,"hidden");removeClass(document.body,"blur")}}}function handleEscape(ev){var help=getHelpElement(false);var search=searchState.outputElement();if(help&&!hasClass(help,"hidden")){displayHelp(false,ev,help)}else if(search&&!hasClass(search,"hidden")){searchState.clearInputTimeout();ev.preventDefault();searchState.hideResults(search)}searchState.defocus();hideThemeButtonState()}var disableShortcuts=getSettingValue("disable-shortcuts")==="true";function handleShortcut(ev){if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement.tagName==="INPUT"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":displayHelp(false,ev);ev.preventDefault();searchState.focus();break;case"+":case"-":ev.preventDefault();toggleAllDocs();break;case"?":displayHelp(true,ev);break;case"t":case"T":displayHelp(false,ev);ev.preventDefault();var themePicker=getThemePickerElement();themePicker.click();themePicker.focus();break;default:if(getThemePickerElement().parentNode.contains(ev.target)){handleThemeKeyDown(ev)}}}}function handleThemeKeyDown(ev){var active=document.activeElement;var themes=getThemesElement();switch(getVirtualKey(ev)){case"ArrowUp":ev.preventDefault();if(active.previousElementSibling&&ev.target.id!==THEME_PICKER_ELEMENT_ID){active.previousElementSibling.focus()}else{showThemeButtonState();themes.lastElementChild.focus()}break;case"ArrowDown":ev.preventDefault();if(active.nextElementSibling&&ev.target.id!==THEME_PICKER_ELEMENT_ID){active.nextElementSibling.focus()}else{showThemeButtonState();themes.firstElementChild.focus()}break;case"Enter":case"Return":case"Space":if(ev.target.id===THEME_PICKER_ELEMENT_ID&&themes.style.display==="none"){ev.preventDefault();showThemeButtonState();themes.firstElementChild.focus()}break;case"Home":ev.preventDefault();themes.firstElementChild.focus();break;case"End":ev.preventDefault();themes.lastElementChild.focus();break}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);(function(){var x=document.getElementsByClassName("version-selector");if(x.length>0){x[0].onchange=function(){var i,match,url=document.location.href,stripped="",len=window.rootPath.match(/\.\.\//g).length+1;for(i=0;i"+""+"
"+code.outerHTML+"
";list.appendChild(display)}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}function labelForToggleButton(sectionIsCollapsed){if(sectionIsCollapsed){return"+"}return"\u2212"}function toggleAllDocs(){var innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}var sectionIsCollapsed=false;if(hasClass(innerToggle,"will-expand")){removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("rustdoc-toggle"),function(e){if(!hasClass(e,"type-contents-toggle")){e.open=true}});innerToggle.title="collapse all docs"}else{addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("rustdoc-toggle"),function(e){if(e.parentNode.id!=="main"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});sectionIsCollapsed=true;innerToggle.title="expand all docs"}innerToggle.children[0].innerText=labelForToggleButton(sectionIsCollapsed)}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}(function(){var toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}var hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";var hideImplementors=getSettingValue("auto-collapse-implementors")!=="false";var hideImplementations=getSettingValue("auto-hide-trait-implementations")!=="false";var hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function openImplementors(id){var list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),function(e){e.open=true})}}if(!hideImplementations){openImplementors("trait-implementations-list");openImplementors("blanket-implementations-list")}if(!hideImplementors){openImplementors("implementors-list")}onEachLazy(document.getElementsByClassName("rustdoc-toggle"),function(e){if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}});var pageId=getPageId();if(pageId!==null){expandSection(pageId)}}());(function(){var lineNumbersFunc=function(){};if(getSettingValue("line-numbers")==="true"){lineNumbersFunc=function(x){var count=x.textContent.split("\n").length;var elems=[];for(var i=0;ithe rustdoc book.";var container=document.createElement("div");var shortcuts=[["?","Show this help dialog"],["S","Focus the search field"],["T","Focus the theme picker menu"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(function(x){return"
"+x[0].split(" ").map(function(y,index){return(index&1)===0?""+y+"":" "+y+" "}).join("")+"
"+x[1]+"
"}).join("");var div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";var infos=["Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + * -> vec)","Search multiple things at once by splitting your query with comma (e.g., \ + str,u8 or String,struct:Vec,test)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for items inside another one by searching for a path: vec::Vec",].map(function(x){return"

"+x+"

"}).join("");var div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;container.appendChild(book_info);container.appendChild(div_shortcuts);container.appendChild(div_infos);popup.appendChild(container);insertAfter(popup,searchState.outputElement());buildHelperPopup=function(){}};onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){var reset_button_timeout=null;window.copy_path=function(but){var parent=but.parentElement;var path=[];onEach(parent.childNodes,function(child){if(child.tagName==='A'){path.push(child.textContent)}});var el=document.createElement('textarea');el.value='use '+path.join('::')+';';el.setAttribute('readonly','');el.style.position='absolute';el.style.left='-9999px';document.body.appendChild(el);el.select();document.execCommand('copy');document.body.removeChild(el);but.children[0].style.display='none';var tmp;if(but.childNodes.length<2){tmp=document.createTextNode('✓');but.appendChild(tmp)}else{onEachLazy(but.childNodes,function(e){if(e.nodeType===Node.TEXT_NODE){tmp=e;return true}});tmp.textContent='✓'}if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){tmp.textContent='';reset_button_timeout=null;but.children[0].style.display=""}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/mkdir/all.html b/mkdir/all.html new file mode 100644 index 000000000..768ea4c06 --- /dev/null +++ b/mkdir/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/mkdir/fn.main.html b/mkdir/fn.main.html new file mode 100644 index 000000000..5beede494 --- /dev/null +++ b/mkdir/fn.main.html @@ -0,0 +1,3 @@ +main in mkdir - Rust + +

Function mkdir::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/mkdir/index.html b/mkdir/index.html new file mode 100644 index 000000000..a7a2238a0 --- /dev/null +++ b/mkdir/index.html @@ -0,0 +1,4 @@ +mkdir - Rust + +

Crate mkdir[][src]

Functions

+
main
\ No newline at end of file diff --git a/mkdir/sidebar-items.js b/mkdir/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/mkdir/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/mkfifo/all.html b/mkfifo/all.html new file mode 100644 index 000000000..86815d4ad --- /dev/null +++ b/mkfifo/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/mkfifo/fn.main.html b/mkfifo/fn.main.html new file mode 100644 index 000000000..4720e7995 --- /dev/null +++ b/mkfifo/fn.main.html @@ -0,0 +1,3 @@ +main in mkfifo - Rust + +

Function mkfifo::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/mkfifo/index.html b/mkfifo/index.html new file mode 100644 index 000000000..c676fdadb --- /dev/null +++ b/mkfifo/index.html @@ -0,0 +1,4 @@ +mkfifo - Rust + +

Crate mkfifo[][src]

Functions

+
main
\ No newline at end of file diff --git a/mkfifo/sidebar-items.js b/mkfifo/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/mkfifo/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/mknod/all.html b/mknod/all.html new file mode 100644 index 000000000..1d00049dd --- /dev/null +++ b/mknod/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/mknod/fn.main.html b/mknod/fn.main.html new file mode 100644 index 000000000..0bbaa65fa --- /dev/null +++ b/mknod/fn.main.html @@ -0,0 +1,3 @@ +main in mknod - Rust + +

Function mknod::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/mknod/index.html b/mknod/index.html new file mode 100644 index 000000000..59ff86dea --- /dev/null +++ b/mknod/index.html @@ -0,0 +1,4 @@ +mknod - Rust + +

Crate mknod[][src]

Functions

+
main
\ No newline at end of file diff --git a/mknod/sidebar-items.js b/mknod/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/mknod/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/mktemp/all.html b/mktemp/all.html new file mode 100644 index 000000000..59d544cc4 --- /dev/null +++ b/mktemp/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/mktemp/fn.main.html b/mktemp/fn.main.html new file mode 100644 index 000000000..6af8eb816 --- /dev/null +++ b/mktemp/fn.main.html @@ -0,0 +1,3 @@ +main in mktemp - Rust + +

Function mktemp::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/mktemp/index.html b/mktemp/index.html new file mode 100644 index 000000000..3db16fe52 --- /dev/null +++ b/mktemp/index.html @@ -0,0 +1,4 @@ +mktemp - Rust + +

Crate mktemp[][src]

Functions

+
main
\ No newline at end of file diff --git a/mktemp/sidebar-items.js b/mktemp/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/mktemp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/more/all.html b/more/all.html new file mode 100644 index 000000000..9ffa2f96c --- /dev/null +++ b/more/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/more/fn.main.html b/more/fn.main.html new file mode 100644 index 000000000..dfeca6af4 --- /dev/null +++ b/more/fn.main.html @@ -0,0 +1,3 @@ +main in more - Rust + +

Function more::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/more/index.html b/more/index.html new file mode 100644 index 000000000..1c94c1aed --- /dev/null +++ b/more/index.html @@ -0,0 +1,4 @@ +more - Rust + +

Crate more[][src]

Functions

+
main
\ No newline at end of file diff --git a/more/sidebar-items.js b/more/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/more/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/mv/all.html b/mv/all.html new file mode 100644 index 000000000..155148fc3 --- /dev/null +++ b/mv/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/mv/fn.main.html b/mv/fn.main.html new file mode 100644 index 000000000..b653a62ee --- /dev/null +++ b/mv/fn.main.html @@ -0,0 +1,3 @@ +main in mv - Rust + +

Function mv::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/mv/index.html b/mv/index.html new file mode 100644 index 000000000..70eb1dfa3 --- /dev/null +++ b/mv/index.html @@ -0,0 +1,4 @@ +mv - Rust + +

Crate mv[][src]

Functions

+
main
\ No newline at end of file diff --git a/mv/sidebar-items.js b/mv/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/mv/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/nice/all.html b/nice/all.html new file mode 100644 index 000000000..8dfc2c88f --- /dev/null +++ b/nice/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/nice/fn.main.html b/nice/fn.main.html new file mode 100644 index 000000000..d9f15725a --- /dev/null +++ b/nice/fn.main.html @@ -0,0 +1,3 @@ +main in nice - Rust + +

Function nice::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/nice/index.html b/nice/index.html new file mode 100644 index 000000000..0344fce44 --- /dev/null +++ b/nice/index.html @@ -0,0 +1,4 @@ +nice - Rust + +

Crate nice[][src]

Functions

+
main
\ No newline at end of file diff --git a/nice/sidebar-items.js b/nice/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/nice/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/nl/all.html b/nl/all.html new file mode 100644 index 000000000..359ef03e9 --- /dev/null +++ b/nl/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/nl/fn.main.html b/nl/fn.main.html new file mode 100644 index 000000000..45608db65 --- /dev/null +++ b/nl/fn.main.html @@ -0,0 +1,3 @@ +main in nl - Rust + +

Function nl::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/nl/index.html b/nl/index.html new file mode 100644 index 000000000..4b1d34633 --- /dev/null +++ b/nl/index.html @@ -0,0 +1,4 @@ +nl - Rust + +

Crate nl[][src]

Functions

+
main
\ No newline at end of file diff --git a/nl/sidebar-items.js b/nl/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/nl/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/nohup/all.html b/nohup/all.html new file mode 100644 index 000000000..db8127d03 --- /dev/null +++ b/nohup/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/nohup/fn.main.html b/nohup/fn.main.html new file mode 100644 index 000000000..b1c9bee7a --- /dev/null +++ b/nohup/fn.main.html @@ -0,0 +1,3 @@ +main in nohup - Rust + +

Function nohup::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/nohup/index.html b/nohup/index.html new file mode 100644 index 000000000..2b1a72022 --- /dev/null +++ b/nohup/index.html @@ -0,0 +1,4 @@ +nohup - Rust + +

Crate nohup[][src]

Functions

+
main
\ No newline at end of file diff --git a/nohup/sidebar-items.js b/nohup/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/nohup/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/normalize.css b/normalize.css new file mode 100644 index 000000000..6d692b50c --- /dev/null +++ b/normalize.css @@ -0,0 +1,2 @@ + /*! normalize.css v3.0.0 | MIT License | git.io/normalize */ +html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0} \ No newline at end of file diff --git a/noscript.css b/noscript.css new file mode 100644 index 000000000..aea68efbc --- /dev/null +++ b/noscript.css @@ -0,0 +1 @@ + #main .attributes{margin-left:0 !important;}#copy-path{display:none;} \ No newline at end of file diff --git a/noto-sans-kr-v13-korean-regular-LICENSE.txt b/noto-sans-kr-v13-korean-regular-LICENSE.txt new file mode 100644 index 000000000..922d5fdc1 --- /dev/null +++ b/noto-sans-kr-v13-korean-regular-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/noto-sans-kr-v13-korean-regular.woff b/noto-sans-kr-v13-korean-regular.woff new file mode 100644 index 000000000..01d6b6b54 Binary files /dev/null and b/noto-sans-kr-v13-korean-regular.woff differ diff --git a/nproc/all.html b/nproc/all.html new file mode 100644 index 000000000..652bfa670 --- /dev/null +++ b/nproc/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/nproc/fn.main.html b/nproc/fn.main.html new file mode 100644 index 000000000..aef976171 --- /dev/null +++ b/nproc/fn.main.html @@ -0,0 +1,3 @@ +main in nproc - Rust + +

Function nproc::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/nproc/index.html b/nproc/index.html new file mode 100644 index 000000000..dd00f3a64 --- /dev/null +++ b/nproc/index.html @@ -0,0 +1,4 @@ +nproc - Rust + +

Crate nproc[][src]

Functions

+
main
\ No newline at end of file diff --git a/nproc/sidebar-items.js b/nproc/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/nproc/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/numfmt/all.html b/numfmt/all.html new file mode 100644 index 000000000..d46f35978 --- /dev/null +++ b/numfmt/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/numfmt/fn.main.html b/numfmt/fn.main.html new file mode 100644 index 000000000..77fc0f929 --- /dev/null +++ b/numfmt/fn.main.html @@ -0,0 +1,3 @@ +main in numfmt - Rust + +

Function numfmt::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/numfmt/index.html b/numfmt/index.html new file mode 100644 index 000000000..2e4695e10 --- /dev/null +++ b/numfmt/index.html @@ -0,0 +1,4 @@ +numfmt - Rust + +

Crate numfmt[][src]

Functions

+
main
\ No newline at end of file diff --git a/numfmt/sidebar-items.js b/numfmt/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/numfmt/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/od/all.html b/od/all.html new file mode 100644 index 000000000..00621064f --- /dev/null +++ b/od/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/od/fn.main.html b/od/fn.main.html new file mode 100644 index 000000000..fd9df8bd4 --- /dev/null +++ b/od/fn.main.html @@ -0,0 +1,3 @@ +main in od - Rust + +

Function od::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/od/index.html b/od/index.html new file mode 100644 index 000000000..ac3e142f0 --- /dev/null +++ b/od/index.html @@ -0,0 +1,4 @@ +od - Rust + +

Crate od[][src]

Functions

+
main
\ No newline at end of file diff --git a/od/sidebar-items.js b/od/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/od/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/paste/all.html b/paste/all.html new file mode 100644 index 000000000..7fc4f1754 --- /dev/null +++ b/paste/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/paste/fn.main.html b/paste/fn.main.html new file mode 100644 index 000000000..0610344a8 --- /dev/null +++ b/paste/fn.main.html @@ -0,0 +1,3 @@ +main in paste - Rust + +

Function paste::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/paste/index.html b/paste/index.html new file mode 100644 index 000000000..72fe39f99 --- /dev/null +++ b/paste/index.html @@ -0,0 +1,4 @@ +paste - Rust + +

Crate paste[][src]

Functions

+
main
\ No newline at end of file diff --git a/paste/sidebar-items.js b/paste/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/paste/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/pathchk/all.html b/pathchk/all.html new file mode 100644 index 000000000..e0375f2c0 --- /dev/null +++ b/pathchk/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/pathchk/fn.main.html b/pathchk/fn.main.html new file mode 100644 index 000000000..f132bae1f --- /dev/null +++ b/pathchk/fn.main.html @@ -0,0 +1,3 @@ +main in pathchk - Rust + +

Function pathchk::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/pathchk/index.html b/pathchk/index.html new file mode 100644 index 000000000..ae9bbec96 --- /dev/null +++ b/pathchk/index.html @@ -0,0 +1,4 @@ +pathchk - Rust + +

Crate pathchk[][src]

Functions

+
main
\ No newline at end of file diff --git a/pathchk/sidebar-items.js b/pathchk/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/pathchk/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/pinky/all.html b/pinky/all.html new file mode 100644 index 000000000..f34995f1e --- /dev/null +++ b/pinky/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/pinky/fn.main.html b/pinky/fn.main.html new file mode 100644 index 000000000..d91961846 --- /dev/null +++ b/pinky/fn.main.html @@ -0,0 +1,3 @@ +main in pinky - Rust + +

Function pinky::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/pinky/index.html b/pinky/index.html new file mode 100644 index 000000000..cfae1f808 --- /dev/null +++ b/pinky/index.html @@ -0,0 +1,4 @@ +pinky - Rust + +

Crate pinky[][src]

Functions

+
main
\ No newline at end of file diff --git a/pinky/sidebar-items.js b/pinky/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/pinky/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/pr/all.html b/pr/all.html new file mode 100644 index 000000000..48cf8e3e4 --- /dev/null +++ b/pr/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/pr/fn.main.html b/pr/fn.main.html new file mode 100644 index 000000000..070810470 --- /dev/null +++ b/pr/fn.main.html @@ -0,0 +1,3 @@ +main in pr - Rust + +

Function pr::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/pr/index.html b/pr/index.html new file mode 100644 index 000000000..00481df69 --- /dev/null +++ b/pr/index.html @@ -0,0 +1,4 @@ +pr - Rust + +

Crate pr[][src]

Functions

+
main
\ No newline at end of file diff --git a/pr/sidebar-items.js b/pr/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/pr/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/printenv/all.html b/printenv/all.html new file mode 100644 index 000000000..727e1022f --- /dev/null +++ b/printenv/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/printenv/fn.main.html b/printenv/fn.main.html new file mode 100644 index 000000000..32d7750b8 --- /dev/null +++ b/printenv/fn.main.html @@ -0,0 +1,3 @@ +main in printenv - Rust + +

Function printenv::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/printenv/index.html b/printenv/index.html new file mode 100644 index 000000000..608a33af7 --- /dev/null +++ b/printenv/index.html @@ -0,0 +1,4 @@ +printenv - Rust + +

Crate printenv[][src]

Functions

+
main
\ No newline at end of file diff --git a/printenv/sidebar-items.js b/printenv/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/printenv/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/printf/all.html b/printf/all.html new file mode 100644 index 000000000..209ba4657 --- /dev/null +++ b/printf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/printf/fn.main.html b/printf/fn.main.html new file mode 100644 index 000000000..d4fd40059 --- /dev/null +++ b/printf/fn.main.html @@ -0,0 +1,3 @@ +main in printf - Rust + +

Function printf::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/printf/index.html b/printf/index.html new file mode 100644 index 000000000..154353b40 --- /dev/null +++ b/printf/index.html @@ -0,0 +1,4 @@ +printf - Rust + +

Crate printf[][src]

Functions

+
main
\ No newline at end of file diff --git a/printf/sidebar-items.js b/printf/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/printf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/ptx/all.html b/ptx/all.html new file mode 100644 index 000000000..a2fb1e8a2 --- /dev/null +++ b/ptx/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/ptx/fn.main.html b/ptx/fn.main.html new file mode 100644 index 000000000..41e7d4dbe --- /dev/null +++ b/ptx/fn.main.html @@ -0,0 +1,3 @@ +main in ptx - Rust + +

Function ptx::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/ptx/index.html b/ptx/index.html new file mode 100644 index 000000000..77af34299 --- /dev/null +++ b/ptx/index.html @@ -0,0 +1,4 @@ +ptx - Rust + +

Crate ptx[][src]

Functions

+
main
\ No newline at end of file diff --git a/ptx/sidebar-items.js b/ptx/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/ptx/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/pwd/all.html b/pwd/all.html new file mode 100644 index 000000000..80e36588c --- /dev/null +++ b/pwd/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/pwd/fn.main.html b/pwd/fn.main.html new file mode 100644 index 000000000..e30f4e9da --- /dev/null +++ b/pwd/fn.main.html @@ -0,0 +1,3 @@ +main in pwd - Rust + +

Function pwd::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/pwd/index.html b/pwd/index.html new file mode 100644 index 000000000..420e0046e --- /dev/null +++ b/pwd/index.html @@ -0,0 +1,4 @@ +pwd - Rust + +

Crate pwd[][src]

Functions

+
main
\ No newline at end of file diff --git a/pwd/sidebar-items.js b/pwd/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/pwd/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/readlink/all.html b/readlink/all.html new file mode 100644 index 000000000..42b45fcd6 --- /dev/null +++ b/readlink/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/readlink/fn.main.html b/readlink/fn.main.html new file mode 100644 index 000000000..ddb09dfcb --- /dev/null +++ b/readlink/fn.main.html @@ -0,0 +1,3 @@ +main in readlink - Rust + +

Function readlink::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/readlink/index.html b/readlink/index.html new file mode 100644 index 000000000..7b51d9f55 --- /dev/null +++ b/readlink/index.html @@ -0,0 +1,4 @@ +readlink - Rust + +

Crate readlink[][src]

Functions

+
main
\ No newline at end of file diff --git a/readlink/sidebar-items.js b/readlink/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/readlink/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/realpath/all.html b/realpath/all.html new file mode 100644 index 000000000..682e3f295 --- /dev/null +++ b/realpath/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/realpath/fn.main.html b/realpath/fn.main.html new file mode 100644 index 000000000..b0c8a1ee5 --- /dev/null +++ b/realpath/fn.main.html @@ -0,0 +1,3 @@ +main in realpath - Rust + +

Function realpath::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/realpath/index.html b/realpath/index.html new file mode 100644 index 000000000..4043bb05e --- /dev/null +++ b/realpath/index.html @@ -0,0 +1,4 @@ +realpath - Rust + +

Crate realpath[][src]

Functions

+
main
\ No newline at end of file diff --git a/realpath/sidebar-items.js b/realpath/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/realpath/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/relpath/all.html b/relpath/all.html new file mode 100644 index 000000000..2c5a07ddf --- /dev/null +++ b/relpath/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/relpath/fn.main.html b/relpath/fn.main.html new file mode 100644 index 000000000..0c04e46d7 --- /dev/null +++ b/relpath/fn.main.html @@ -0,0 +1,3 @@ +main in relpath - Rust + +

Function relpath::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/relpath/index.html b/relpath/index.html new file mode 100644 index 000000000..f05be568b --- /dev/null +++ b/relpath/index.html @@ -0,0 +1,4 @@ +relpath - Rust + +

Crate relpath[][src]

Functions

+
main
\ No newline at end of file diff --git a/relpath/sidebar-items.js b/relpath/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/relpath/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/rm/all.html b/rm/all.html new file mode 100644 index 000000000..f0f28aaa5 --- /dev/null +++ b/rm/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/rm/fn.main.html b/rm/fn.main.html new file mode 100644 index 000000000..d01042a1a --- /dev/null +++ b/rm/fn.main.html @@ -0,0 +1,3 @@ +main in rm - Rust + +

Function rm::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/rm/index.html b/rm/index.html new file mode 100644 index 000000000..5ee7d7729 --- /dev/null +++ b/rm/index.html @@ -0,0 +1,4 @@ +rm - Rust + +

Crate rm[][src]

Functions

+
main
\ No newline at end of file diff --git a/rm/sidebar-items.js b/rm/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/rm/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/rmdir/all.html b/rmdir/all.html new file mode 100644 index 000000000..823814052 --- /dev/null +++ b/rmdir/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/rmdir/fn.main.html b/rmdir/fn.main.html new file mode 100644 index 000000000..71f14ddc4 --- /dev/null +++ b/rmdir/fn.main.html @@ -0,0 +1,3 @@ +main in rmdir - Rust + +

Function rmdir::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/rmdir/index.html b/rmdir/index.html new file mode 100644 index 000000000..5473cc37f --- /dev/null +++ b/rmdir/index.html @@ -0,0 +1,4 @@ +rmdir - Rust + +

Crate rmdir[][src]

Functions

+
main
\ No newline at end of file diff --git a/rmdir/sidebar-items.js b/rmdir/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/rmdir/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/runcon/all.html b/runcon/all.html new file mode 100644 index 000000000..5c05ef95d --- /dev/null +++ b/runcon/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/runcon/fn.main.html b/runcon/fn.main.html new file mode 100644 index 000000000..3589608e1 --- /dev/null +++ b/runcon/fn.main.html @@ -0,0 +1,3 @@ +main in runcon - Rust + +

Function runcon::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/runcon/index.html b/runcon/index.html new file mode 100644 index 000000000..f7dfee765 --- /dev/null +++ b/runcon/index.html @@ -0,0 +1,4 @@ +runcon - Rust + +

Crate runcon[][src]

Functions

+
main
\ No newline at end of file diff --git a/runcon/sidebar-items.js b/runcon/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/runcon/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/rust-logo.png b/rust-logo.png new file mode 100644 index 000000000..74b4bd695 Binary files /dev/null and b/rust-logo.png differ diff --git a/rustdoc.css b/rustdoc.css new file mode 100644 index 000000000..9b9be7988 --- /dev/null +++ b/rustdoc.css @@ -0,0 +1 @@ + @font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular.woff2") format("woff2"),url("FiraSans-Regular.woff") format('woff');font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium.woff2") format("woff2"),url("FiraSans-Medium.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular.ttf.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It.ttf.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold.ttf.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular.ttf.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It.ttf.woff") format('woff');font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold.ttf.woff") format('woff');font-display:swap;}@font-face {font-family:'Noto Sans KR';src:url("noto-sans-kr-v13-korean-regular.woff") format("woff");font-display:swap;unicode-range:U+A960-A97F,U+AC00-D7AF,U+D7B0-D7FF;}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}html{content:"";}@media (prefers-color-scheme:light){html{content:"light";}}@media (prefers-color-scheme:dark){html{content:"dark";}}body{font:16px/1.4 "Source Serif 4","Noto Sans KR",serif;margin:0;position:relative;padding:10px 15px 20px 15px;-webkit-font-feature-settings:"kern","liga";-moz-font-feature-settings:"kern","liga";font-feature-settings:"kern","liga";}h1{font-size:1.5em;}h2{font-size:1.4em;}h3{font-size:1.3em;}h1,h2,h3,h4{font-weight:500;margin:20px 0 15px 0;padding-bottom:6px;}h1.fqn{display:flex;border-bottom:1px dashed;margin-top:0;padding-left:1px;}h1.fqn>.in-band>a:hover{text-decoration:underline;}#main>h2,#main>h3,#main>h4{border-bottom:1px solid;}h3.code-header,h4.code-header{font-size:1em;font-weight:600;border:none;padding:0;margin:0;}.impl,.impl-items .method,.methods .method,.impl-items .type,.methods .type,.impl-items .associatedconstant,.methods .associatedconstant,.impl-items .associatedtype,.methods .associatedtype{flex-basis:100%;font-weight:600;margin-top:16px;margin-bottom:10px;position:relative;}.impl,.method.trait-impl,.type.trait-impl,.associatedconstant.trait-impl,.associatedtype.trait-impl{padding-left:15px;}div.impl-items>div{padding-left:0;}h1,h2,h3,h4,.sidebar,a.source,.search-input,.search-results .result-name,.content table td:first-child>a,div.item-list .out-of-band,span.since,#source-sidebar,#sidebar-toggle,details.rustdoc-toggle>summary::before,details.undocumented>summary::before,div.impl-items>div:not(.docblock):not(.item-info),.content ul.crate a.crate,a.srclink,#main>ul.docblock>li>a{font-family:"Fira Sans",Arial,sans-serif;}.content ul.crate a.crate{font-size:16px/1.6;}ol,ul{padding-left:25px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.6em;}p{margin:0 0 .6em 0;}summary{outline:none;}td,th{padding:0;}table{border-collapse:collapse;}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;}details:not(.rustdoc-toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.1em;}.docblock pre code,.docblock-short pre code{padding:0;padding-right:1ex;}pre{padding:14px;}.source .content pre{padding:20px;}img{max-width:100%;}li{position:relative;}.source .content{margin-top:50px;max-width:none;overflow:visible;margin-left:0px;}nav.sub{font-size:16px;text-transform:uppercase;}.sidebar{width:200px;position:fixed;left:0;top:0;bottom:0;overflow:auto;}*{scrollbar-width:initial;}.sidebar{scrollbar-width:thin;}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;}.sidebar .block>ul>li{margin-right:-10px;}.content,nav{max-width:960px;}.hidden{display:none !important;}.logo-container{height:100px;width:100px;position:relative;margin:20px auto;display:block;margin-top:10px;}.logo-container>img{max-width:100px;max-height:100px;position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:block;}.sidebar .location{border:1px solid;font-size:17px;margin:30px 10px 20px 10px;text-align:center;word-wrap:break-word;font-weight:inherit;padding:0;}.sidebar .version{font-size:15px;text-align:center;border-bottom:1px solid;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word;}.location:empty{border:none;}.location a:first-of-type{font-weight:500;}.location a:hover{text-decoration:underline;}.block{padding:0;margin-bottom:14px;}.block h2,.block h3{text-align:center;}.block ul,.block li{margin:0 10px;padding:0;list-style:none;}.block a{display:block;text-overflow:ellipsis;overflow:hidden;line-height:15px;padding:7px 5px;font-size:14px;font-weight:300;transition:border 500ms ease-out;}.sidebar-title{border-top:1px solid;border-bottom:1px solid;text-align:center;font-size:17px;margin-bottom:5px;font-weight:inherit;padding:0;}.sidebar-links{margin-bottom:15px;}.sidebar-links>a{padding-left:10px;width:100%;}.sidebar-menu{display:none;}.content{padding:15px 0;}.source .content pre.rust{white-space:pre;overflow:auto;padding-left:0;}.rustdoc .example-wrap{display:inline-flex;margin-bottom:10px;}.example-wrap{position:relative;width:100%;}.example-wrap>pre.line-number{overflow:initial;border:1px solid;padding:13px 8px;text-align:right;border-top-left-radius:5px;border-bottom-left-radius:5px;}.rustdoc:not(.source) .example-wrap>pre.rust{width:100%;overflow-x:auto;}.rustdoc .example-wrap>pre{margin:0;}#search{margin-left:230px;position:relative;}#results>table{width:100%;table-layout:fixed;}.content>.example-wrap pre.line-numbers{position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.line-numbers span{cursor:pointer;}.docblock-short{overflow-wrap:anywhere;}.docblock-short p{display:inline;}.docblock-short p{overflow:hidden;text-overflow:ellipsis;margin:0;}.docblock>:not(pre)>code,.docblock-short>:not(pre)>code{white-space:pre-wrap;}.docblock h1,.docblock h2,.docblock h3,.docblock h4,.docblock h5{border-bottom:1px solid;}.top-doc .docblock h1{font-size:1.3em;}.top-doc .docblock h2{font-size:1.15em;}.top-doc .docblock h3,.top-doc .docblock h4,.top-doc .docblock h5{font-size:1em;}.docblock h1{font-size:1em;}.docblock h2{font-size:0.95em;}.docblock h3,.docblock h4,.docblock h5{font-size:0.9em;}.docblock{margin-left:24px;position:relative;}.content .out-of-band{flex-grow:0;text-align:right;font-size:23px;margin:0px;padding:0 0 0 12px;font-weight:normal;}.method>.code-header,.trait-impl>.code-header,.invisible>.code-header{max-width:calc(100% - 41px);display:block;flex-grow:1;}.invisible{width:100%;display:inline-block;}.content .in-band{flex-grow:1;margin:0px;padding:0px;}.in-band>code,.in-band>.code-header{display:inline-block;}#main{position:relative;}#main>.since{top:inherit;font-family:"Fira Sans",Arial,sans-serif;}.content table:not(.table-display){border-spacing:0 5px;}.content td{vertical-align:top;}.content td:first-child{padding-right:20px;}.content td p:first-child{margin-top:0;}.content td h1,.content td h2{margin-left:0;font-size:1.1em;}.content tr:first-child td{border-top:0;}.docblock table{margin:.5em 0;width:calc(100% - 2px);border:1px dashed;}.docblock table td{padding:.5em;border:1px dashed;}.docblock table th{padding:.5em;text-align:left;border:1px solid;}.fields+table{margin-bottom:1em;}.content .item-list{list-style-type:none;padding:0;}.content .multi-column{-moz-column-count:5;-moz-column-gap:2.5em;-webkit-column-count:5;-webkit-column-gap:2.5em;column-count:5;column-gap:2.5em;}.content .multi-column li{width:100%;display:inline-block;}.content>.methods>.method{font-size:1em;position:relative;}.content .method .where,.content .fn .where,.content .where.fmt-newline{display:block;font-size:0.8em;}.content .methods>div:not(.notable-traits):not(.method){margin-left:40px;margin-bottom:15px;}.content .docblock>.impl-items{margin-left:20px;margin-top:-34px;}.content .docblock>.impl-items .table-display{margin:0;}.content .docblock>.impl-items table td{padding:0;}.content .docblock>.impl-items .table-display,.impl-items table td{border:none;}.content .item-info code{font-size:90%;}.content .item-info{position:relative;margin-left:33px;margin-top:-6px;}.sub-variant>div>.item-info{margin-top:initial;}.content .item-info::before{content:'⬑';font-size:25px;position:absolute;top:0px;left:-19px;}.content .impl-items .method,.content .impl-items>.type,.impl-items>.associatedconstant,.impl-items>.associatedtype,.content .impl-items details>summary>.type,.impl-items details>summary>.associatedconstant,.impl-items details>summary>.associatedtype{margin-left:20px;}.content .impl-items .docblock,.content .impl-items .item-info{margin-bottom:.6em;}.content .impl-items>.item-info{margin-left:40px;}.methods>.item-info,.content .impl-items>.item-info{margin-top:-8px;}.impl-items{flex-basis:100%;}#main>.item-info{margin-top:0;}nav:not(.sidebar){border-bottom:1px solid;padding-bottom:10px;margin-bottom:10px;}nav.main{padding:20px 0;text-align:center;}nav.main .current{border-top:1px solid;border-bottom:1px solid;}nav.main .separator{border:1px solid;display:inline-block;height:23px;margin:0 20px;}nav.sum{text-align:right;}nav.sub form{display:inline;}nav.sub,.content{margin-left:230px;}a{text-decoration:none;background:transparent;}.small-section-header:hover>.anchor{display:initial;}.in-band:hover>.anchor,.impl:hover>.anchor,.method.trait-impl:hover>.anchor,.type.trait-impl:hover>.anchor,.associatedconstant.trait-impl:hover>.anchor,.associatedtype.trait-impl:hover>.anchor{display:inline-block;position:absolute;}.anchor{display:none;position:absolute;left:-7px;}.anchor.field{left:-5px;}.small-section-header>.anchor{left:-28px;padding-right:10px;}.anchor:before{content:'\2002\00a7\2002';}.docblock a:not(.srclink):not(.test-arrow):hover,.docblock-short a:not(.srclink):not(.test-arrow):hover,.item-info a{text-decoration:underline;}.invisible>.srclink,.method>.code-header+.srclink{position:absolute;top:0;right:0;font-size:17px;font-weight:normal;}.block a.current.crate{font-weight:500;}.search-container{position:relative;}.search-container>div{display:inline-flex;width:calc(100% - 63px);}#crate-search{min-width:115px;margin-top:5px;padding:6px;padding-right:19px;flex:none;border:0;border-right:0;border-radius:4px 0 0 4px;outline:none;cursor:pointer;border-right:1px solid;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;text-overflow:"";background-repeat:no-repeat;background-color:transparent;background-size:20px;background-position:calc(100% - 1px) 56%;}.search-container>.top-button{position:absolute;right:0;top:10px;}.search-input{-moz-box-sizing:border-box !important;box-sizing:border-box !important;outline:none;border:none;border-radius:1px;margin-top:5px;padding:10px 16px;font-size:17px;transition:border-color 300ms ease;transition:border-radius 300ms ease-in-out;transition:box-shadow 300ms ease-in-out;width:100%;}#crate-search+.search-input{border-radius:0 1px 1px 0;width:calc(100% - 32px);}.search-input:focus{border-radius:2px;border:0;outline:0;}.search-results{display:none;padding-bottom:2em;}.search-results.active{display:block;clear:both;}.search-results .desc>span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;display:block;}.search-results>a{display:block;width:100%;margin-left:2px;margin-right:2px;border-bottom:1px solid #aaa3;}.search-results>a>div{display:flex;flex-flow:row wrap;}.search-results .result-name,.search-results div.desc,.search-results .result-description{width:50%;}.search-results .result-name{padding-right:1em;}.search-results .result-name>span{display:inline-block;margin:0;font-weight:normal;}body.blur>:not(#help){filter:blur(8px);-webkit-filter:blur(8px);opacity:.7;}#help{width:100%;height:100vh;position:fixed;top:0;left:0;display:flex;justify-content:center;align-items:center;}#help>div{flex:0 0 auto;box-shadow:0 0 6px rgba(0,0,0,.2);width:550px;height:auto;border:1px solid;}#help dt{float:left;clear:left;display:block;margin-right:0.5rem;}#help>div>span{text-align:center;display:block;margin:10px 0;font-size:18px;border-bottom:1px solid #ccc;padding-bottom:4px;margin-bottom:6px;}#help dd{margin:5px 35px;}#help .infos{padding-left:0;}#help h1,#help h2{margin-top:0;}#help>div div{width:50%;float:left;padding:0 20px 20px 17px;;}.stab{display:table;border-width:1px;border-style:solid;padding:3px;margin-bottom:5px;font-size:90%;}.stab p{display:inline;}.stab summary{display:list-item;}.stab .emoji{font-size:1.5em;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.module-item .stab,.import-item .stab{border-radius:3px;display:inline-block;font-size:80%;line-height:1.2;margin-bottom:0;margin-right:.3em;padding:2px;vertical-align:text-bottom;}.module-item.unstable,.import-item.unstable{opacity:0.65;}.since{font-weight:normal;font-size:initial;position:absolute;right:0;top:0;}.impl-items .since,.impl .since,.methods .since{flex-grow:0;padding-left:12px;padding-right:6px;position:initial;}.impl-items .srclink,.impl .srclink,.methods .srclink{flex-grow:0;font-size:17px;font-weight:normal;}.impl-items code,.impl code,.methods code{flex-grow:1;}.has-srclink{display:flex;flex-basis:100%;font-size:16px;margin-bottom:12px;justify-content:space-between;}.variants_table{width:100%;}.variants_table tbody tr td:first-child{width:1%;}td.summary-column{width:100%;}.summary{padding-right:0px;}pre.rust .question-mark{font-weight:bold;}a.test-arrow{display:inline-block;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:130%;top:5px;right:5px;z-index:1;}a.test-arrow:hover{text-decoration:none;}.section-header:hover a:before{position:absolute;left:-25px;padding-right:10px;content:'\2002\00a7\2002';}.section-header:hover a{text-decoration:none;}.section-header a{color:inherit;}.code-attribute{font-weight:300;}.since+.srclink{display:table-cell;padding-left:10px;}.item-spacer{width:100%;height:12px;}.out-of-band>span.since{position:initial;font-size:20px;margin-right:5px;}.sub-variant,.sub-variant>h3{margin-top:0px !important;padding-top:1px;}#main>details>.sub-variant>h3{font-size:15px;margin-left:25px;margin-bottom:5px;}.sub-variant>div{margin-left:20px;margin-bottom:10px;}.sub-variant>div>span{display:block;position:relative;}.toggle-label{display:inline-block;margin-left:4px;margin-top:3px;}.docblock>.section-header:first-child{margin-left:15px;margin-top:0;}.docblock>.section-header:first-child:hover>a:before{left:-10px;}#main>.variant,#main>.structfield{display:block;}:target>code,:target>.code-header{opacity:1;}.information{position:absolute;left:-25px;margin-top:7px;z-index:1;}.tooltip{position:relative;display:inline-block;cursor:pointer;}.tooltip::after{display:none;text-align:center;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;font-size:16px;}.tooltip.ignore::after{content:"This example is not tested";}.tooltip.compile_fail::after{content:"This example deliberately fails to compile";}.tooltip.should_panic::after{content:"This example panics";}.tooltip.edition::after{content:"This code runs with edition " attr(data-edition);}.tooltip::before{content:" ";position:absolute;top:50%;left:16px;margin-top:-5px;border-width:5px;border-style:solid;display:none;}.tooltip:hover::before,.tooltip:hover::after{display:inline;}.tooltip.compile_fail,.tooltip.should_panic,.tooltip.ignore{font-weight:bold;font-size:20px;}.notable-traits-tooltip{display:inline-block;cursor:pointer;}.notable-traits:hover .notable-traits-tooltiptext,.notable-traits .notable-traits-tooltiptext.force-tooltip{display:inline-block;}.notable-traits .notable-traits-tooltiptext{display:none;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;z-index:10;font-size:16px;cursor:default;position:absolute;border:1px solid;}.notable-traits-tooltip::after{content:"\00a0\00a0\00a0";}.notable-traits .notable,.notable-traits .docblock{margin:0;}.notable-traits .notable{margin:0;margin-bottom:13px;font-size:19px;font-weight:600;}.notable-traits .docblock code.content{margin:0;padding:0;font-size:20px;}pre.rust.rust-example-rendered{position:relative;}pre.rust{tab-size:4;-moz-tab-size:4;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#titles{height:35px;}#titles>button{float:left;width:33.3%;text-align:center;font-size:18px;cursor:pointer;border:0;border-top:2px solid;}#titles>button:not(:last-child){margin-right:1px;width:calc(33.3% - 1px);}#titles>button>div.count{display:inline-block;font-size:16px;}.notable-traits{cursor:pointer;z-index:2;margin-left:5px;}#all-types{text-align:center;border:1px solid;margin:0 10px;margin-bottom:10px;display:block;border-radius:7px;}#all-types>p{margin:5px 0;}#sidebar-toggle{position:fixed;top:30px;left:300px;z-index:10;padding:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;cursor:pointer;font-weight:bold;transition:left .5s;font-size:1.2em;border:1px solid;border-left:0;}#source-sidebar{position:fixed;top:0;bottom:0;left:0;width:300px;z-index:1;overflow:auto;transition:left .5s;border-right:1px solid;}#source-sidebar>.title{font-size:1.5em;text-align:center;border-bottom:1px solid;margin-bottom:6px;}.theme-picker{position:absolute;left:211px;top:19px;}.theme-picker button{outline:none;}#settings-menu,#help-button{position:absolute;top:10px;}#settings-menu{right:0;outline:none;}#theme-picker,#settings-menu,#help-button,#copy-path{padding:4px;width:27px;height:29px;border:1px solid;border-radius:3px;cursor:pointer;}#help-button{right:30px;font-family:"Fira Sans",Arial,sans-serif;text-align:center;font-size:17px;padding-top:2px;}#copy-path{background:initial;margin-left:10px;padding:0;padding-left:2px;border:0;}#theme-choices{display:none;position:absolute;left:0;top:28px;border:1px solid;border-radius:3px;z-index:1;cursor:pointer;}#theme-choices>button{border:none;width:100%;padding:4px 8px;text-align:center;background:rgba(0,0,0,0);}#theme-choices>button:not(:first-child){border-top:1px solid;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px;border-radius:3px;box-shadow:inset 0 -1px 0;cursor:default;}.hidden-by-impl-hider,.hidden-by-usual-hider{display:none !important;}#implementations-list>h3>span.in-band{width:100%;}.table-display{width:100%;border:0;border-collapse:collapse;border-spacing:0;font-size:16px;}.table-display tr td:first-child{padding-right:0;}.table-display tr td:last-child{float:right;}.table-display .out-of-band{position:relative;font-size:19px;display:block;}#implementors-list>.impl-items .table-display .out-of-band{font-size:17px;}.table-display td:hover .anchor{display:block;top:2px;left:-5px;}#main>ul{padding-left:10px;}#main>ul>li{list-style:none;}.non-exhaustive{margin-bottom:1em;}div.children{padding-left:27px;display:none;}div.name{cursor:pointer;position:relative;margin-left:16px;}div.files>a{display:block;padding:0 3px;}div.files>a:hover,div.name:hover{background-color:#a14b4b;}div.name.expand+.children{display:block;}div.name::before{content:"\25B6";padding-left:4px;font-size:0.7em;position:absolute;left:-16px;top:4px;}div.name.expand::before{transform:rotate(90deg);left:-15px;top:2px;}details.rustdoc-toggle>summary.hideme{cursor:pointer;}details.rustdoc-toggle>summary,details.undocumented>summary{list-style:none;}details.rustdoc-toggle>summary::-webkit-details-marker,details.rustdoc-toggle>summary::marker,details.undocumented>summary::-webkit-details-marker,details.undocumented>summary::marker{display:none;}details.rustdoc-toggle>summary.hideme>span{margin-left:9px;}details.rustdoc-toggle>summary::before{content:"[+]";font-weight:300;font-size:0.8em;letter-spacing:1px;cursor:pointer;}details.rustdoc-toggle.top-doc>summary,details.rustdoc-toggle.top-doc>summary::before,details.rustdoc-toggle.non-exhaustive>summary,details.rustdoc-toggle.non-exhaustive>summary::before{font-family:'Fira Sans';font-size:16px;}details.non-exhaustive{margin-bottom:8px;}details.rustdoc-toggle>summary.hideme::before{position:relative;}details.rustdoc-toggle>summary:not(.hideme)::before{position:absolute;left:-23px;top:3px;}.impl-items>details.rustdoc-toggle>summary:not(.hideme)::before,.undocumented>details.rustdoc-toggle>summary:not(.hideme)::before{position:absolute;left:-2px;}details.rustdoc-toggle[open] >summary.hideme{position:absolute;}details.rustdoc-toggle,details.undocumented{position:relative;}details.rustdoc-toggle[open] >summary.hideme>span{display:none;}details.rustdoc-toggle[open] >summary::before{content:"[−]";display:inline;}details.undocumented>summary::before{content:"[+] Show hidden undocumented items";cursor:pointer;font-size:16px;font-weight:300;}details.undocumented[open] >summary::before{content:"[−] Hide undocumented items";}@media (min-width:701px){.docblock>.information:first-child>.tooltip{margin-top:16px;}}@media (max-width:700px){body{padding-top:0px;}.rustdoc>.sidebar{height:45px;min-height:40px;margin:0;margin-left:-15px;padding:0 15px;position:static;z-index:11;}.sidebar>.location{float:right;margin:0px;margin-top:2px;padding:3px 10px 1px 10px;min-height:39px;background:inherit;text-align:left;font-size:24px;}.sidebar .location:empty{padding:0;}.sidebar .logo-container{width:35px;height:35px;margin-top:5px;margin-bottom:5px;float:left;margin-left:50px;}.sidebar .logo-container>img{max-width:35px;max-height:35px;}.sidebar-menu{position:fixed;z-index:10;font-size:2rem;cursor:pointer;width:45px;left:0;text-align:center;display:block;border-bottom:1px solid;border-right:1px solid;height:45px;}.rustdoc.source>.sidebar>.sidebar-menu{display:none;}.sidebar-elems{position:fixed;z-index:1;top:45px;bottom:0;width:246px;left:-246px;overflow-y:auto;border-right:1px solid;}.sidebar>.block.version{border-bottom:none;margin-top:12px;margin-bottom:0;}nav.sub{width:calc(100% - 32px);float:right;}.content{margin-left:0px;}#main,#search{margin-top:45px;padding:0;}#search{margin-left:0;}.content .impl-items .method,.content .impl-items>.type,.impl-items>.associatedconstant,.impl-items>.associatedtype{display:flex;}.anchor{display:none !important;}.theme-picker{left:10px;top:54px;z-index:1;}.notable-traits{position:absolute;left:-22px;top:24px;}#titles>button>div.count{float:left;width:100%;}#titles{height:50px;}.sidebar.mobile{position:fixed;width:100%;margin-left:0;background-color:rgba(0,0,0,0);height:100%;}.sidebar.mobile>div.version{overflow:hidden;max-height:33px;}.sidebar{width:calc(100% + 30px);}.show-it{left:0;}.show-it>.block.items{margin:8px 0;}.show-it>.block.items>ul{margin:0;}.show-it>.block.items>ul>li{text-align:center;margin:2px 0;}.show-it>.block.items>ul>li>a{font-size:21px;}#sidebar-filler{position:fixed;left:45px;width:calc(100% - 45px);top:0;height:45px;z-index:-1;border-bottom:1px solid;}#main>details.rustdoc-toggle>summary::before,#main>div>details.rustdoc-toggle>summary::before{left:-11px;}#all-types{margin:10px;}#sidebar-toggle{top:100px;width:30px;font-size:1.5rem;text-align:center;padding:0;}#source-sidebar{z-index:11;}#main>.line-numbers{margin-top:0;}.notable-traits .notable-traits-tooltiptext{left:0;top:100%;}#help-button{display:none;}.search-container>div{width:calc(100% - 32px);}.search-results>a{border-bottom:1px solid #aaa9;padding:5px 0px;}.search-results .result-name,.search-results div.desc,.search-results .result-description{width:100%;}.search-results div.desc,.search-results .result-description{padding-left:2em;}}@media print{nav.sub,.content .out-of-band{display:none;}}@media (max-width:464px){#titles,#titles>button{height:73px;}#main,#search{margin-top:100px;}#main>table:not(.table-display) td{word-break:break-word;width:50%;}.search-container>div{display:block;width:calc(100% - 37px);}#crate-search{width:100%;border-radius:4px;border:0;}#crate-search+.search-input{width:calc(100% + 71px);margin-left:-36px;}#theme-picker,#settings-menu{padding:5px;width:31px;height:31px;}#theme-picker{margin-top:-2px;}#settings-menu{top:7px;}.docblock{margin-left:12px;}} \ No newline at end of file diff --git a/search-index.js b/search-index.js new file mode 100644 index 000000000..2573c6e68 --- /dev/null +++ b/search-index.js @@ -0,0 +1,207 @@ +var searchIndex = JSON.parse('{\ +"arch":{"doc":"","t":[5],"n":["main"],"q":["arch"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"base32":{"doc":"","t":[5],"n":["main"],"q":["base32"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"base64":{"doc":"","t":[5],"n":["main"],"q":["base64"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"basename":{"doc":"","t":[5],"n":["main"],"q":["basename"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"basenc":{"doc":"","t":[5],"n":["main"],"q":["basenc"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"cat":{"doc":"","t":[5],"n":["main"],"q":["cat"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"chcon":{"doc":"","t":[5],"n":["main"],"q":["chcon"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"chgrp":{"doc":"","t":[5],"n":["main"],"q":["chgrp"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"chmod":{"doc":"","t":[5],"n":["main"],"q":["chmod"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"chown":{"doc":"","t":[5],"n":["main"],"q":["chown"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"chroot":{"doc":"","t":[5],"n":["main"],"q":["chroot"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"cksum":{"doc":"","t":[5],"n":["main"],"q":["cksum"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"comm":{"doc":"","t":[5],"n":["main"],"q":["comm"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"coreutils":{"doc":"","t":[6,17,5,5,5,5,5,5,5],"n":["UtilityMap","VERSION","binary_path","gen_completions","gen_coreutils_app","main","name","usage","util_map"],"q":["coreutils","","","","","","","",""],"d":["","","","Prints completions for the utility in the first parameter …","","","","",""],"i":[0,0,0,0,0,0,0,0,0],"f":[null,null,[[],["pathbuf",3]],[[["str",15],["hashmap",3]]],[[["str",15],["hashmap",3]],["app",3]],[[]],[[["path",3]],["str",15]],[[["hashmap",3],["str",15]]],[[],[["str",15],["hashmap",3]]]],"p":[]},\ +"cp":{"doc":"","t":[5],"n":["main"],"q":["cp"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"csplit":{"doc":"","t":[5],"n":["main"],"q":["csplit"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"cut":{"doc":"","t":[5],"n":["main"],"q":["cut"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"date":{"doc":"","t":[5],"n":["main"],"q":["date"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"dd":{"doc":"","t":[5],"n":["main"],"q":["dd"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"df":{"doc":"","t":[5],"n":["main"],"q":["df"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"dircolors":{"doc":"","t":[5],"n":["main"],"q":["dircolors"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"dirname":{"doc":"","t":[5],"n":["main"],"q":["dirname"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"du":{"doc":"","t":[5],"n":["main"],"q":["du"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"echo":{"doc":"","t":[5],"n":["main"],"q":["echo"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"env":{"doc":"","t":[5],"n":["main"],"q":["env"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"expand":{"doc":"","t":[5],"n":["main"],"q":["expand"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"expr":{"doc":"","t":[5],"n":["main"],"q":["expr"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"factor":{"doc":"","t":[5],"n":["main"],"q":["factor"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"false":{"doc":"","t":[5],"n":["main"],"q":["false"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"fmt":{"doc":"","t":[5],"n":["main"],"q":["fmt"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"fold":{"doc":"","t":[5],"n":["main"],"q":["fold"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"groups":{"doc":"","t":[5],"n":["main"],"q":["groups"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"hashsum":{"doc":"","t":[5],"n":["main"],"q":["hashsum"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"head":{"doc":"","t":[5],"n":["main"],"q":["head"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"hostid":{"doc":"","t":[5],"n":["main"],"q":["hostid"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"hostname":{"doc":"","t":[5],"n":["main"],"q":["hostname"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"id":{"doc":"","t":[5],"n":["main"],"q":["id"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"install":{"doc":"","t":[5],"n":["main"],"q":["install"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"join":{"doc":"","t":[5],"n":["main"],"q":["join"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"kill":{"doc":"","t":[5],"n":["main"],"q":["kill"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"libstdbuf":{"doc":"","t":[5],"n":["__stdbuf"],"q":["libstdbuf"],"d":["Safety"],"i":[0],"f":[[[]]],"p":[]},\ +"link":{"doc":"","t":[5],"n":["main"],"q":["link"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"ln":{"doc":"","t":[5],"n":["main"],"q":["ln"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"logname":{"doc":"","t":[5],"n":["main"],"q":["logname"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"ls":{"doc":"","t":[5],"n":["main"],"q":["ls"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"mkdir":{"doc":"","t":[5],"n":["main"],"q":["mkdir"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"mkfifo":{"doc":"","t":[5],"n":["main"],"q":["mkfifo"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"mknod":{"doc":"","t":[5],"n":["main"],"q":["mknod"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"mktemp":{"doc":"","t":[5],"n":["main"],"q":["mktemp"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"more":{"doc":"","t":[5],"n":["main"],"q":["more"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"mv":{"doc":"","t":[5],"n":["main"],"q":["mv"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"nice":{"doc":"","t":[5],"n":["main"],"q":["nice"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"nl":{"doc":"","t":[5],"n":["main"],"q":["nl"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"nohup":{"doc":"","t":[5],"n":["main"],"q":["nohup"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"nproc":{"doc":"","t":[5],"n":["main"],"q":["nproc"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"numfmt":{"doc":"","t":[5],"n":["main"],"q":["numfmt"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"od":{"doc":"","t":[5],"n":["main"],"q":["od"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"paste":{"doc":"","t":[5],"n":["main"],"q":["paste"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"pathchk":{"doc":"","t":[5],"n":["main"],"q":["pathchk"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"pinky":{"doc":"","t":[5],"n":["main"],"q":["pinky"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"pr":{"doc":"","t":[5],"n":["main"],"q":["pr"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"printenv":{"doc":"","t":[5],"n":["main"],"q":["printenv"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"printf":{"doc":"","t":[5],"n":["main"],"q":["printf"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"ptx":{"doc":"","t":[5],"n":["main"],"q":["ptx"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"pwd":{"doc":"","t":[5],"n":["main"],"q":["pwd"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"readlink":{"doc":"","t":[5],"n":["main"],"q":["readlink"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"realpath":{"doc":"","t":[5],"n":["main"],"q":["realpath"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"relpath":{"doc":"","t":[5],"n":["main"],"q":["relpath"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"rm":{"doc":"","t":[5],"n":["main"],"q":["rm"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"rmdir":{"doc":"","t":[5],"n":["main"],"q":["rmdir"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"runcon":{"doc":"","t":[5],"n":["main"],"q":["runcon"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"seq":{"doc":"","t":[5],"n":["main"],"q":["seq"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"shred":{"doc":"","t":[5],"n":["main"],"q":["shred"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"shuf":{"doc":"","t":[5],"n":["main"],"q":["shuf"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"sleep":{"doc":"","t":[5],"n":["main"],"q":["sleep"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"sort":{"doc":"","t":[5],"n":["main"],"q":["sort"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"split":{"doc":"","t":[5],"n":["main"],"q":["split"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"stat":{"doc":"","t":[5],"n":["main"],"q":["stat"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"stdbuf":{"doc":"","t":[5],"n":["main"],"q":["stdbuf"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"sum":{"doc":"","t":[5],"n":["main"],"q":["sum"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"sync":{"doc":"","t":[5],"n":["main"],"q":["sync"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"tac":{"doc":"","t":[5],"n":["main"],"q":["tac"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"tail":{"doc":"","t":[5],"n":["main"],"q":["tail"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"tee":{"doc":"","t":[5],"n":["main"],"q":["tee"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"test":{"doc":"","t":[5],"n":["main"],"q":["test"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"timeout":{"doc":"","t":[5],"n":["main"],"q":["timeout"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"touch":{"doc":"","t":[5],"n":["main"],"q":["touch"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"tr":{"doc":"","t":[5],"n":["main"],"q":["tr"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"true":{"doc":"","t":[5],"n":["main"],"q":["true"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"truncate":{"doc":"","t":[5],"n":["main"],"q":["truncate"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"tsort":{"doc":"","t":[5],"n":["main"],"q":["tsort"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"tty":{"doc":"","t":[5],"n":["main"],"q":["tty"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"uname":{"doc":"","t":[5],"n":["main"],"q":["uname"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"unexpand":{"doc":"","t":[5],"n":["main"],"q":["unexpand"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"uniq":{"doc":"","t":[5],"n":["main"],"q":["uniq"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"unlink":{"doc":"","t":[5],"n":["main"],"q":["unlink"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"uptime":{"doc":"","t":[5],"n":["main"],"q":["uptime"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"users":{"doc":"","t":[5],"n":["main"],"q":["users"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"uu_arch":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_arch",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_base32":{"doc":"","t":[0,5,5,3,5,11,11,12,11,11,5,5,12,11,0,5,12,11,11,11,12,7,7,7,7],"n":["base_common","uu_app","uumain","Config","base_app","borrow","borrow_mut","decode","from","from","get_input","handle_input","ignore_garbage","into","options","parse_base_cmd_args","to_read","try_from","try_into","type_id","wrap_cols","DECODE","FILE","IGNORE_GARBAGE","WRAP"],"q":["uu_base32","","","uu_base32::base_common","","","","","","","","","","","","","","","","","","uu_base32::base_common::options","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,1,1,1,1,1,0,0,1,1,0,0,1,1,1,1,1,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,[[["str",15],["str",15]],["app",3]],[[]],[[]],null,[[]],[[["str",15],["argmatches",3]],[["result",4],["config",3],["string",3]]],[[["config",3],["stdin",3]],[["read",8],["box",3]]],[[["bool",15],["str",15],["usize",15],["option",4],["format",4]]],null,[[]],null,[[["str",15]],[["result",4],["config",3],["string",3]]],null,[[],["result",4]],[[],["result",4]],[[],["typeid",3]],null,null,null,null,null],"p":[[3,"Config"]]},\ +"uu_base64":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_base64",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_basename":{"doc":"","t":[0,5,5,7,7,7,7],"n":["options","uu_app","uumain","MULTIPLE","NAME","SUFFIX","ZERO"],"q":["uu_basename","","","uu_basename::options","","",""],"d":["","","","","","",""],"i":[0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null],"p":[]},\ +"uu_basenc":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_basenc",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_cat":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_cat",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_chcon":{"doc":"","t":[0,5,5,7,7,7,7,7,7,7,0,0,0,7,7,7,7,7,7,7],"n":["options","uu_app","uumain","RANGE","RECURSIVE","REFERENCE","ROLE","TYPE","USER","VERBOSE","dereference","preserve_root","sym_links","DEREFERENCE","NO_DEREFERENCE","NO_PRESERVE_ROOT","PRESERVE_ROOT","FOLLOW_ARG_DIR_SYM_LINK","FOLLOW_DIR_SYM_LINKS","NO_FOLLOW_SYM_LINKS"],"q":["uu_chcon","","","uu_chcon::options","","","","","","","","","","uu_chcon::options::dereference","","uu_chcon::options::preserve_root","","uu_chcon::options::sym_links","",""],"d":["","","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_chgrp":{"doc":"","t":[0,0,5,5,3,8,3,11,11,11,11,11,11,11,11,11,11,11,5,5,11,11,5,5,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,5,7,7,7,7,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7],"n":["entries","options","uu_app","uumain","Group","Locate","Passwd","as_inner","as_inner","belongs_to","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","from","from","get_groups","get_groups_gnu","gid","gid","gid2grp","grp2gid","into","into","into_inner","into_inner","locate","locate","locate","locate","locate","name","name","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","uid","uid2usr","user_dir","user_info","user_passwd","user_shell","usr2uid","ARG_FILES","ARG_GROUP","RECURSIVE","REFERENCE","dereference","preserve_root","traverse","verbosity","DEREFERENCE","NO_DEREFERENCE","NO_PRESERVE","PRESERVE","EVERY","NO_TRAVERSE","TRAVERSE","CHANGES","QUIET","SILENT","VERBOSE"],"q":["uu_chgrp","","","","uu_chgrp::entries","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uu_chgrp::options","","","","","","","","uu_chgrp::options::dereference","","uu_chgrp::options::preserve_root","","uu_chgrp::options::traverse","","","uu_chgrp::options::verbosity","","",""],"d":["Get password/group file entry","","","","","Fetch desired entry.","","","","This is a wrapper function for libc::getgrouplist.","","","","","","","","","From: …","The list of group IDs returned from GNU’s groups and GNU…","AKA group.gr_gid","AKA passwd.pw_gid","","","","","","","","","","","","AKA group.gr_name","AKA passwd.pw_name","","","","","","","","AKA passwd.pw_uid","","AKA passwd.pw_dir","AKA passwd.pw_gecos","AKA passwd.pw_passwd","AKA passwd.pw_shell","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,1,2,2,1,2,1,2,2,2,1,2,0,0,1,2,0,0,1,2,1,2,3,1,1,2,2,1,2,2,1,2,1,2,1,2,2,0,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,null,[[],["app",3]],[[],["i32",15]],null,null,null,[[],["group",3]],[[],["passwd",3]],[[],[["vec",3],["u32",15],["global",3]]],[[]],[[]],[[]],[[]],[[],["passwd",3]],[[]],[[]],[[]],[[],[["result",4],["vec",3],["error",3]]],[[["u32",15],["option",4]],[["result",4],["vec",3],["error",3]]],[[],["u32",15]],[[],["u32",15]],[[["u32",15]],[["string",3],["error",3],["result",4]]],[[["str",15]],[["result",4],["u32",15],["error",3]]],[[]],[[]],[[],["group",3]],[[],["passwd",3]],[[],[["result",4],["error",3]]],[[["u32",15]],[["error",3],["result",4],["group",3]]],[[["str",15]],[["error",3],["result",4],["group",3]]],[[["str",15]],[["error",3],["result",4],["passwd",3]]],[[["u32",15]],[["error",3],["result",4],["passwd",3]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["u32",15]],[[["u32",15]],[["string",3],["error",3],["result",4]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[["str",15]],[["result",4],["u32",15],["error",3]]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"p":[[3,"Group"],[3,"Passwd"],[8,"Locate"]]},\ +"uu_chmod":{"doc":"","t":[5,5,5,5],"n":["is_symlink","strip_minus_from_mode","uu_app","uumain"],"q":["uu_chmod","","",""],"d":["","","",""],"i":[0,0,0,0],"f":[[[["path",3],["asref",8]],["bool",15]],[[["vec",3]],["bool",15]],[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_chown":{"doc":"","t":[3,8,3,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,5,5,3,8,3,5,5,5,5,10,5,5,7,7,7,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7],"n":["Group","Locate","Passwd","as_inner","as_inner","belongs_to","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","entries","from","from","gid","gid","into","into","into_inner","into_inner","locate","locate","locate","locate","locate","name","name","options","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","uid","user_dir","user_info","user_passwd","user_shell","uu_app","uumain","Group","Locate","Passwd","get_groups","get_groups_gnu","gid2grp","grp2gid","locate","uid2usr","usr2uid","FROM","RECURSIVE","REFERENCE","dereference","preserve_root","traverse","verbosity","DEREFERENCE","NO_DEREFERENCE","NO_PRESERVE","PRESERVE","EVERY","NO_TRAVERSE","TRAVERSE","CHANGES","QUIET","SILENT","VERBOSE"],"q":["uu_chown","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uu_chown::entries","","","","","","","","","","uu_chown::options","","","","","","","uu_chown::options::dereference","","uu_chown::options::preserve_root","","uu_chown::options::traverse","","","uu_chown::options::verbosity","","",""],"d":["","Fetch desired entry.","","","","This is a wrapper function for libc::getgrouplist.","","","","","","","Get password/group file entry","","","AKA group.gr_gid","AKA passwd.pw_gid","","","","","","","","","","AKA group.gr_name","AKA passwd.pw_name","","","","","","","","","AKA passwd.pw_uid","AKA passwd.pw_dir","AKA passwd.pw_gecos","AKA passwd.pw_passwd","AKA passwd.pw_shell","","","","Fetch desired entry.","","From: …","The list of group IDs returned from GNU’s groups and GNU…","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,1,2,2,1,2,1,2,2,2,0,1,2,1,2,1,2,1,2,3,1,1,2,2,1,2,0,2,1,2,1,2,1,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,null,null,[[],["group",3]],[[],["passwd",3]],[[],[["u32",15],["global",3],["vec",3]]],[[]],[[]],[[]],[[]],[[],["passwd",3]],[[]],null,[[]],[[]],[[],["u32",15]],[[],["u32",15]],[[]],[[]],[[],["group",3]],[[],["passwd",3]],[[],[["result",4],["error",3]]],[[["u32",15]],[["error",3],["result",4],["group",3]]],[[["str",15]],[["error",3],["result",4],["group",3]]],[[["str",15]],[["passwd",3],["error",3],["result",4]]],[[["u32",15]],[["passwd",3],["error",3],["result",4]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],null,[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["u32",15]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[],[["str",15],["cow",4]]],[[],["app",3]],[[],["i32",15]],null,null,null,[[],[["vec",3],["error",3],["result",4]]],[[["u32",15],["option",4]],[["vec",3],["error",3],["result",4]]],[[["u32",15]],[["error",3],["result",4],["string",3]]],[[["str",15]],[["result",4],["u32",15],["error",3]]],[[],[["result",4],["error",3]]],[[["u32",15]],[["error",3],["result",4],["string",3]]],[[["str",15]],[["result",4],["u32",15],["error",3]]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"p":[[3,"Group"],[3,"Passwd"],[8,"Locate"]]},\ +"uu_chroot":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_chroot",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_cksum":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_cksum",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_comm":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_comm",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_cp":{"doc":"","t":[13,13,4,13,13,13,4,13,13,4,6,13,4,13,13,13,13,13,13,13,13,13,13,13,13,13,13,3,4,13,4,13,13,6,6,13,13,13,13,6,6,4,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,5],"n":["Always","AttrOnly","Attribute","Auto","Backup","Clobber","ClobberMode","Context","Copy","CopyMode","CopyResult","Directory","Error","Error","File","Force","Interactive","InvalidArgument","IoErr","IoErrContext","Link","Links","Mode","Never","NoClobber","NotAllFilesCopied","NotImplemented","Options","OverwriteMode","Ownership","ReflinkMode","RemoveDestination","Skipped","Source","SourceSlice","Sparse","Standard","StripPrefixError","SymLink","Target","TargetSlice","TargetType","Timestamps","Update","WalkDirErr","Xattr","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","cause","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","eq","eq","eq","eq","ficlone","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_str","into","into","into","into","into","into","into","into","localize_to_target","ne","paths_refer_to_same_file","to_owned","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","uu_app","uumain","verify_target_type"],"q":["uu_cp","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","","","Invalid arguments to backup","[Default] Always overwrite existing files","Specifies whether when overwrite files","","","","","","","General copy error","","","Prompt before overwriting a file","Result of a skipped file","Simple io::Error wrapper","Wrapper for io::Error with path context","","","","","Never overwrite a file","Represents the state when a non-fatal error has occurred …","All standard options are included as an an implementation …","Re-usable, extensible copy options","Specifies whether when overwrite files","","Possible arguments for --reflink.","","Result of a skipped file","","","","","Simple std::path::StripPrefixError wrapper","","","","Specifies the expected file type of copy target","","","Simple walkdir::Error wrapper","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Remove the root prefix from source and prefix it with …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Generate an error message if target is not the correct …"],"i":[1,2,0,1,3,4,0,5,2,0,0,6,0,3,6,7,4,3,3,3,2,5,5,1,4,3,3,0,0,5,0,7,3,0,0,2,7,3,2,0,0,0,5,2,3,5,6,2,8,3,7,4,1,5,6,2,8,3,7,4,1,5,3,7,4,1,5,7,4,1,5,7,4,1,5,0,3,3,6,2,8,3,3,3,3,3,3,3,7,4,1,5,5,6,2,8,3,7,4,1,5,0,4,0,7,4,1,5,3,6,2,8,3,7,4,1,5,6,2,8,3,7,4,1,5,6,2,8,3,7,4,1,5,0,0,0],"f":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[["option",4],["error",8]]],[[],["clobbermode",4]],[[],["overwritemode",4]],[[],["reflinkmode",4]],[[],["attribute",4]],[[]],[[]],[[]],[[]],[[["clobbermode",4]],["bool",15]],[[["overwritemode",4]],["bool",15]],[[["reflinkmode",4]],["bool",15]],[[["attribute",4]],["bool",15]],[[["c_int",6]],["c_int",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[["str",15]],["error",4]],[[["string",3]],["error",4]],[[["error",3]],["error",4]],[[["error",3]],["error",4]],[[["stripprefixerror",3]],["error",4]],[[["context",3],["str",15],["error",3]],["error",4]],[[]],[[]],[[]],[[]],[[]],[[["str",15]],[["attribute",4],["copyresult",6]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[["path",3]],[["copyresult",6],["pathbuf",3]]],[[["overwritemode",4]],["bool",15]],[[["path",3]],[["bool",15],["result",6]]],[[]],[[]],[[]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],[[["path",3],["targettype",4]],["copyresult",6]]],"p":[[4,"ReflinkMode"],[4,"CopyMode"],[4,"Error"],[4,"OverwriteMode"],[4,"Attribute"],[4,"TargetType"],[4,"ClobberMode"],[3,"Options"]]},\ +"uu_csplit":{"doc":"","t":[3,11,11,5,11,11,11,11,11,5,5],"n":["CsplitOptions","borrow","borrow_mut","csplit","from","into","try_from","try_into","type_id","uu_app","uumain"],"q":["uu_csplit","","","","","","","","","",""],"d":["Command line options for csplit.","","","Splits a file into severals according to the command line …","","","","","","",""],"i":[0,1,1,0,1,1,1,1,1,0,0],"f":[null,[[]],[[]],[[["pattern",4],["vec",3],["csplitoptions",3]],[["result",4],["cspliterror",4]]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]]],"p":[[3,"CsplitOptions"]]},\ +"uu_cut":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_cut",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_date":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_date",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_dd":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_dd",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_df":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_df",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_dircolors":{"doc":"","t":[13,4,13,8,13,11,11,11,11,10,11,5,11,10,10,11,11,11,5,5],"n":["CShell","OutputFmt","Shell","StrUtils","Unknown","borrow","borrow_mut","eq","fmt","fnmatch","from","guess_syntax","into","purify","split_two","try_from","try_into","type_id","uu_app","uumain"],"q":["uu_dircolors","","","","","","","","","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","Remove comments and trim whitespace","Like split_whitespace() but only produce 2 components","","","","",""],"i":[1,0,1,0,1,1,1,1,1,2,1,0,1,2,2,1,1,1,0,0],"f":[null,null,null,null,null,[[]],[[]],[[["outputfmt",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["str",15]],["bool",15]],[[]],[[],["outputfmt",4]],[[]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]]],"p":[[4,"OutputFmt"],[8,"StrUtils"]]},\ +"uu_dirname":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_dirname",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_du":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_du",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_echo":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_echo",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_env":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_env",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_expand":{"doc":"","t":[0,5,5,7,7,7,7],"n":["options","uu_app","uumain","FILES","INITIAL","NO_UTF8","TABS"],"q":["uu_expand","","","uu_expand::options","","",""],"d":["","","","","","",""],"i":[0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null],"p":[]},\ +"uu_expr":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_expr",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_factor":{"doc":"","t":[3,11,11,11,11,11,11,5,11,11,11,11,11,0,11,11,0,11,11,11,11,11,5,5,11,5,17,17,17,5,5],"n":["Factors","add","borrow","borrow_mut","clone","clone_into","eq","factor","fmt","fmt","from","into","ne","numeric","one","push","table","to_owned","to_string","try_from","try_into","type_id","uu_app","uumain","vzip","gcd","CHUNK_SIZE","NEXT_PRIME","PRIME_INVERSIONS_U64","factor","factor_chunk"],"q":["uu_factor","","","","","","","","","","","","","","","","","","","","","","","","","uu_factor::numeric","uu_factor::table","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,0,0,0],"f":[null,[[["u64",15],["u8",15]]],[[]],[[]],[[],["factors",3]],[[]],[[["factors",3]],["bool",15]],[[["u64",15]],["factors",3]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[["factors",3]],["bool",15]],null,[[],["factors",3]],[[["u64",15]]],null,[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],[[]],[[["u64",15]],["u64",15]],null,null,null,[[["u64",15],["factors",3]]],[[]]],"p":[[3,"Factors"]]},\ +"uu_false":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_false",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_fmt":{"doc":"","t":[6,3,11,11,11,11,11,11,11,5,5],"n":["FileOrStdReader","FmtOptions","borrow","borrow_mut","from","into","try_from","try_into","type_id","uu_app","uumain"],"q":["uu_fmt","","","","","","","","","",""],"d":["","","","","","","","","","",""],"i":[0,0,1,1,1,1,1,1,1,0,0],"f":[null,null,[[]],[[]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]]],"p":[[3,"FmtOptions"]]},\ +"uu_fold":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_fold",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_groups":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_groups",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_hashsum":{"doc":"","t":[5,5,5],"n":["uu_app_common","uu_app_custom","uumain"],"q":["uu_hashsum","",""],"d":["","",""],"i":[0,0,0],"f":[[[],["app",3]],[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_head":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_head",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_hostid":{"doc":"","t":[5,5,5],"n":["gethostid","uu_app","uumain"],"q":["uu_hostid","",""],"d":["","",""],"i":[0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_hostname":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_hostname",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_id":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_id",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_install":{"doc":"","t":[3,13,4,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5],"n":["Behavior","Directory","MainFunction","Standard","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","eq","from","from","into","into","mode","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","uu_app","uumain"],"q":["uu_install","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","Create directories","","Install files to locations (primary functionality)","","","","","","","","","","","","Determine the mode for chmod after copy.","","","","","","","","",""],"i":[0,1,0,1,2,1,2,1,1,1,1,2,1,2,1,2,1,2,1,2,1,2,1,0,0],"f":[null,null,null,null,[[]],[[]],[[]],[[]],[[],["mainfunction",4]],[[]],[[["mainfunction",4]],["bool",15]],[[]],[[]],[[]],[[]],[[],["u32",15]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]]],"p":[[4,"MainFunction"],[3,"Behavior"]]},\ +"uu_join":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_join",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_kill":{"doc":"","t":[13,13,4,13,11,11,11,11,11,11,0,11,11,11,11,5,5,7,7,7,7,7],"n":["Kill","List","Mode","Table","borrow","borrow_mut","clone","clone_into","from","into","options","to_owned","try_from","try_into","type_id","uu_app","uumain","LIST","PIDS_OR_SIGNALS","SIGNAL","TABLE","TABLE_OLD"],"q":["uu_kill","","","","","","","","","","","","","","","","","uu_kill::options","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","",""],"i":[1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0],"f":[null,null,null,null,[[]],[[]],[[],["mode",4]],[[]],[[]],[[]],null,[[]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],null,null,null,null,null],"p":[[4,"Mode"]]},\ +"uu_link":{"doc":"","t":[5,0,5,5,7],"n":["normalize_error_message","options","uu_app","uumain","FILES"],"q":["uu_link","","","","uu_link::options"],"d":["","","","",""],"i":[0,0,0,0,0],"f":[[[["error",3]],["string",3]],null,[[],["app",3]],[[],["i32",15]],null],"p":[]},\ +"uu_ln":{"doc":"","t":[13,13,13,4,3,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,5,5],"n":["Force","Interactive","NoClobber","OverwriteMode","Settings","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","eq","fmt","from","from","into","into","is_symlink","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","uu_app","uumain"],"q":["uu_ln","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[1,1,1,0,0,2,1,2,1,1,1,1,1,2,1,2,1,0,1,2,1,2,1,2,1,0,0],"f":[null,null,null,null,null,[[]],[[]],[[]],[[]],[[],["overwritemode",4]],[[]],[[["overwritemode",4]],["bool",15]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[["asref",8],["path",3]],["bool",15]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]]],"p":[[4,"OverwriteMode"],[3,"Settings"]]},\ +"uu_logname":{"doc":"","t":[5,5,5],"n":["getlogin","uu_app","uumain"],"q":["uu_logname","",""],"d":["","",""],"i":[0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_ls":{"doc":"","t":[0,5,5,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7],"n":["options","uu_app","uumain","AUTHOR","COLOR","DIRECTORY","FORMAT","FULL_TIME","HIDE","HIDE_CONTROL_CHARS","IGNORE","IGNORE_BACKUPS","INDICATOR_STYLE","INODE","NO_GROUP","PATHS","QUOTING_STYLE","RECURSIVE","REVERSE","SHOW_CONTROL_CHARS","SORT","TIME","TIME_STYLE","WIDTH","dereference","files","format","indicator_style","quoting","size","sort","time","ALL","ARGS","DIR_ARGS","ALL","ALMOST_ALL","ACROSS","COLUMNS","COMMAS","LONG","LONG_NO_GROUP","LONG_NO_OWNER","LONG_NUMERIC_UID_GID","ONE_LINE","CLASSIFY","FILE_TYPE","SLASH","C","ESCAPE","LITERAL","HUMAN_READABLE","SI","EXTENSION","NONE","SIZE","TIME","VERSION","ACCESS","CHANGE"],"q":["uu_ls","","","uu_ls::options","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uu_ls::options::dereference","","","uu_ls::options::files","","uu_ls::options::format","","","","","","","","uu_ls::options::indicator_style","","","uu_ls::options::quoting","","","uu_ls::options::size","","uu_ls::options::sort","","","","","uu_ls::options::time",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_mkdir":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_mkdir",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_mkfifo":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_mkfifo",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_mknod":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_mknod",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_mktemp":{"doc":"","t":[5,5,5],"n":["dry_exec","uu_app","uumain"],"q":["uu_mktemp","",""],"d":["","",""],"i":[0,0,0],"f":[[[["str",15],["pathbuf",3],["usize",15]],["uresult",6]],[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_more":{"doc":"","t":[0,5,5,17,17,17,17,17,17,17,17,17,17,17,17],"n":["options","uu_app","uumain","CLEAN_PRINT","FILES","FROM_LINE","LINES","LOGICAL","NO_PAUSE","NUMBER","PATTERN","PLAIN","PRINT_OVER","SILENT","SQUEEZE"],"q":["uu_more","","","uu_more::options","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_mv":{"doc":"","t":[3,13,13,13,4,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5],"n":["Behavior","Force","Interactive","NoClobber","OverwriteMode","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","eq","from","from","into","into","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","uu_app","uumain"],"q":["uu_mv","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,1,1,1,0,2,1,2,1,1,1,1,2,1,2,1,1,2,1,2,1,2,1,0,0],"f":[null,null,null,null,null,[[]],[[]],[[]],[[]],[[],["overwritemode",4]],[[]],[[["overwritemode",4]],["bool",15]],[[]],[[]],[[]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]]],"p":[[4,"OverwriteMode"],[3,"Behavior"]]},\ +"uu_nice":{"doc":"","t":[0,5,5,7,7],"n":["options","uu_app","uumain","ADJUSTMENT","COMMAND"],"q":["uu_nice","","","uu_nice::options",""],"d":["","","","",""],"i":[0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null],"p":[]},\ +"uu_nl":{"doc":"","t":[3,11,11,11,11,0,11,11,11,5,5,17,17,17,17,17,17,17,17,17,17,17,17],"n":["Settings","borrow","borrow_mut","from","into","options","try_from","try_into","type_id","uu_app","uumain","BODY_NUMBERING","FILE","FOOTER_NUMBERING","HEADER_NUMBERING","JOIN_BLANK_LINES","LINE_INCREMENT","NO_RENUMBER","NUMBER_FORMAT","NUMBER_SEPARATOR","NUMBER_WIDTH","SECTION_DELIMITER","STARTING_LINE_NUMBER"],"q":["uu_nl","","","","","","","","","","","uu_nl::options","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,1,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[]],[[]],[[]],[[]],null,[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null,null,null],"p":[[3,"Settings"]]},\ +"uu_nohup":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_nohup",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_nproc":{"doc":"","t":[17,5,5],"n":["_SC_NPROCESSORS_CONF","uu_app","uumain"],"q":["uu_nproc","",""],"d":["","",""],"i":[0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_numfmt":{"doc":"","t":[0,0,5,5,3,11,11,5,5,11,11,11,11,12,11,11,11,17,13,17,17,17,17,13,17,17,17,13,3,17,17,4,17,17,13,3,13,11,11,11,11,11,11,11,11,12,12,11,11,11,12,12,11,11,11,12,11,12,12,11,12,11,11,11,11,11,11,11,11,11],"n":["format","options","uu_app","uumain","WhitespaceSplitter","borrow","borrow_mut","div_round","format_and_print","from","into","into_iter","next","s","try_from","try_into","type_id","DELIMITER","Down","FIELD","FIELD_DEFAULT","FROM","FROM_DEFAULT","FromZero","HEADER","HEADER_DEFAULT","NUMBER","Nearest","NumfmtOptions","PADDING","ROUND","RoundMethod","TO","TO_DEFAULT","TowardsZero","TransformOptions","Up","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone_into","delimiter","fields","from","from","from","from","header","into","into","into","padding","round","round","to","to_owned","transform","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id"],"q":["uu_numfmt","","","","uu_numfmt::format","","","","","","","","","","","","","uu_numfmt::options","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","","","Iterate over a line’s fields, where each field is a …","","","Divide numerator by denominator, with rounding.","Format a line of text according to the selected options.","","","","Yield the next field in the input string as a tuple …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,0,0,0,1,1,0,0,1,1,1,1,1,1,1,1,0,2,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,2,0,2,3,4,2,3,4,2,2,2,4,4,3,4,2,3,4,3,4,2,4,2,4,3,2,4,3,4,2,3,4,2,3,4,2],"f":[null,null,[[],["app",3]],[[],["i32",15]],null,[[]],[[]],[[["f64",15],["roundmethod",4]],["f64",15]],[[["str",15],["numfmtoptions",3]],[["string",3],["result",4]]],[[]],[[]],[[]],[[],["option",4]],null,[[],["result",4]],[[],["result",4]],[[],["typeid",3]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[],["roundmethod",4]],[[]],null,null,[[]],[[]],[[]],null,null,[[]],[[]],[[]],null,[[["f64",15]],["f64",15]],null,null,[[]],null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]]],"p":[[3,"WhitespaceSplitter"],[4,"RoundMethod"],[3,"TransformOptions"],[3,"NumfmtOptions"]]},\ +"uu_od":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_od",""],"d":["","parses and validates command line parameters, prepares …"],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_paste":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_paste",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_pathchk":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_pathchk",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_pinky":{"doc":"","t":[8,10,5,5],"n":["Capitalize","capitalize","uu_app","uumain"],"q":["uu_pinky","","",""],"d":["","","",""],"i":[0,1,0,0],"f":[null,[[],["string",3]],[[],["app",3]],[[],["i32",15]]],"p":[[8,"Capitalize"]]},\ +"uu_pr":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_pr",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_printenv":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_printenv",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_printf":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_printf",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_ptx":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_ptx",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_pwd":{"doc":"","t":[5,5,5],"n":["absolute_path","uu_app","uumain"],"q":["uu_pwd","",""],"d":["","",""],"i":[0,0,0],"f":[[[["path",3]],[["result",6],["pathbuf",3]]],[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_readlink":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_readlink",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_realpath":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_realpath",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_relpath":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_relpath",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_rm":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_rm",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_rmdir":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_rmdir",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_runcon":{"doc":"","t":[0,5,5,17,17,17,17,17],"n":["options","uu_app","uumain","COMPUTE","RANGE","ROLE","TYPE","USER"],"q":["uu_runcon","","","uu_runcon::options","","","",""],"d":["","","","","","","",""],"i":[0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null],"p":[]},\ +"uu_seq":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_seq",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_shred":{"doc":"","t":[0,5,5,17,17,17,17,17,17,17,17],"n":["options","uu_app","uumain","EXACT","FILE","FORCE","ITERATIONS","REMOVE","SIZE","VERBOSE","ZERO"],"q":["uu_shred","","","uu_shred::options","","","","","","",""],"d":["","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null],"p":[]},\ +"uu_shuf":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_shuf",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_sleep":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_sleep",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_sort":{"doc":"","t":[4,3,13,13,3,13,13,13,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,11,11,11,11],"n":["GeneralF64ParseResult","GlobalSettings","Infinity","Invalid","Line","NaN","NegInfinity","Number","Output","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","default","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","eq","fmt","fmt","from","from","from","from","init","init","init","init","into","into","into","into","ne","partial_cmp","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","uu_app","uumain","vzip","vzip","vzip","vzip"],"q":["uu_sort","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[0,0,1,1,0,1,1,1,0,2,3,4,1,2,3,4,1,3,4,1,3,4,1,3,2,3,4,1,2,3,4,1,2,3,4,1,1,4,1,2,3,4,1,2,3,4,1,2,3,4,1,1,1,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,0,0,2,3,4,1],"f":[null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["globalsettings",3]],[[],["line",3]],[[],["generalf64parseresult",4]],[[]],[[]],[[]],[[],["globalsettings",3]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["usize",15]]],[[["generalf64parseresult",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[],["usize",15]],[[]],[[]],[[]],[[]],[[["generalf64parseresult",4]],["bool",15]],[[["generalf64parseresult",4]],[["option",4],["ordering",4]]],[[]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],[[]],[[]],[[]],[[]]],"p":[[4,"GeneralF64ParseResult"],[3,"Output"],[3,"GlobalSettings"],[3,"Line"]]},\ +"uu_split":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_split",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_stat":{"doc":"","t":[13,13,17,17,17,17,17,17,13,4,8,3,13,4,13,13,13,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,0,10,10,11,11,11,11,11,11,11,11,11,5,5,12,12,12,12,7,7,7,7,7],"n":["Char","Directive","F_ALTER","F_GROUP","F_LEFT","F_SIGN","F_SPACE","F_ZERO","Integer","OutputType","ScanUtil","Stater","Str","Token","Unknown","Unsigned","UnsignedHex","UnsignedOct","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","eq","eq","fmt","fmt","from","from","from","generate_tokens","group_num","into","into","into","ne","options","scan_char","scan_num","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","uu_app","uumain","flag","format","precision","width","DEREFERENCE","FILE_SYSTEM","FORMAT","PRINTF","TERSE"],"q":["uu_stat","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uu_stat::Token","","","","uu_stat::options","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"i":[1,1,0,0,0,0,0,0,2,0,0,0,2,0,2,2,2,2,3,2,1,3,2,1,2,1,2,1,3,2,1,3,0,3,2,1,1,0,4,4,3,2,1,3,2,1,3,2,1,0,0,5,5,5,5,0,0,0,0,0],"f":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[["outputtype",4]],["bool",15]],[[["token",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[["bool",15],["str",15]],[["result",4],["vec",3],["string",3]]],[[["str",15]],[["cow",4],["str",15]]],[[]],[[]],[[]],[[["token",4]],["bool",15]],null,[[["u32",15]],["option",4]],[[],["option",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null],"p":[[4,"Token"],[4,"OutputType"],[3,"Stater"],[8,"ScanUtil"],[13,"Directive"]]},\ +"uu_stdbuf":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_stdbuf",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_sum":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_sum",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_sync":{"doc":"","t":[0,5,5,7,7],"n":["options","uu_app","uumain","DATA","FILE_SYSTEM"],"q":["uu_sync","","","uu_sync::options",""],"d":["","","","",""],"i":[0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null],"p":[]},\ +"uu_tac":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_tac",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_tail":{"doc":"","t":[0,5,5,7,7,7,7,7,7,7,0,7,7],"n":["options","uu_app","uumain","ARG_FILES","BYTES","FOLLOW","LINES","PID","SLEEP_INT","ZERO_TERM","verbosity","QUIET","VERBOSE"],"q":["uu_tail","","","uu_tail::options","","","","","","","","uu_tail::options::verbosity",""],"d":["","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_tee":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_tee",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_test":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_test",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_timeout":{"doc":"","t":[0,5,5,7,7,7,7,7,7,7],"n":["options","uu_app","uumain","COMMAND","DURATION","FOREGROUND","KILL_AFTER","PRESERVE_STATUS","SIGNAL","VERBOSE"],"q":["uu_timeout","","","uu_timeout::options","","","","","",""],"d":["","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null],"p":[]},\ +"uu_touch":{"doc":"","t":[0,5,5,7,7,7,7,7,7,0,7,7,7],"n":["options","uu_app","uumain","ACCESS","MODIFICATION","NO_CREATE","NO_DEREF","SOURCES","TIME","sources","CURRENT","DATE","REFERENCE"],"q":["uu_touch","","","uu_touch::options","","","","","","","uu_touch::options::sources","",""],"d":["","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_tr":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_tr",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_true":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_true",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_truncate":{"doc":"","t":[0,5,5,7,7,7,7,7],"n":["options","uu_app","uumain","ARG_FILES","IO_BLOCKS","NO_CREATE","REFERENCE","SIZE"],"q":["uu_truncate","","","uu_truncate::options","","","",""],"d":["","","","","","","",""],"i":[0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null],"p":[]},\ +"uu_tsort":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_tsort",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_tty":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_tty",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_uname":{"doc":"","t":[0,5,5,7,7,7,7,7,7,7,7,7],"n":["options","uu_app","uumain","ALL","HWPLATFORM","KERNELNAME","KERNELRELEASE","KERNELVERSION","MACHINE","NODENAME","OS","PROCESSOR"],"q":["uu_uname","","","uu_uname::options","","","","","","","",""],"d":["","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_unexpand":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_unexpand",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_uniq":{"doc":"","t":[0,5,5,7,7,7,7,7,7,7,7,7,7],"n":["options","uu_app","uumain","ALL_REPEATED","CHECK_CHARS","COUNT","GROUP","IGNORE_CASE","REPEATED","SKIP_CHARS","SKIP_FIELDS","UNIQUE","ZERO_TERMINATED"],"q":["uu_uniq","","","uu_uniq::options","","","","","","","","",""],"d":["","","","","","","","","","","","",""],"i":[0,0,0,0,0,0,0,0,0,0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null,null,null,null,null,null,null,null,null,null],"p":[]},\ +"uu_unlink":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_unlink",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_uptime":{"doc":"","t":[0,5,5,7],"n":["options","uu_app","uumain","SINCE"],"q":["uu_uptime","","","uu_uptime::options"],"d":["","","",""],"i":[0,0,0,0],"f":[null,[[],["app",3]],[[],["i32",15]],null],"p":[]},\ +"uu_users":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_users",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_wc":{"doc":"","t":[13,13,4,11,11,11,11,11,11,11,0,11,11,11,11,11,5,5,7,7,7,7,7],"n":["Io","IsDirectory","WcError","borrow","borrow_mut","fmt","fmt","from","from","into","options","source","to_string","try_from","try_into","type_id","uu_app","uumain","BYTES","CHAR","LINES","MAX_LINE_LENGTH","WORDS"],"q":["uu_wc","","","","","","","","","","","","","","","","","","uu_wc::options","","","",""],"d":["","","","","","","","","","","","","","","","","","","","","","",""],"i":[1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,0,0,0,0,0,0,0],"f":[null,null,null,[[]],[[]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["error",3]]],[[]],[[]],null,[[],[["option",4],["error",8]]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["app",3]],[[],["i32",15]],null,null,null,null,null],"p":[[4,"WcError"]]},\ +"uu_who":{"doc":"","t":[5,5],"n":["uu_app","uumain"],"q":["uu_who",""],"d":["",""],"i":[0,0],"f":[[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_whoami":{"doc":"","t":[5,5,5],"n":["exec","uu_app","uumain"],"q":["uu_whoami","",""],"d":["","",""],"i":[0,0,0],"f":[[[]],[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uu_yes":{"doc":"","t":[5,5,5],"n":["exec","uu_app","uumain"],"q":["uu_yes","",""],"d":["","",""],"i":[0,0,0],"f":[[[]],[[],["app",3]],[[],["i32",15]]],"p":[]},\ +"uucore":{"doc":"","t":[8,13,4,13,13,4,13,13,11,14,5,5,0,11,11,11,11,11,11,0,14,14,0,0,0,5,14,11,11,11,11,0,0,5,14,11,11,0,14,14,14,14,14,14,0,0,0,0,0,0,0,14,0,14,14,14,5,14,14,14,14,14,14,0,14,14,11,11,11,11,11,11,14,5,0,0,0,7,7,4,13,13,13,13,11,11,11,11,5,5,11,11,11,5,11,11,11,11,11,3,3,11,11,11,11,12,11,11,11,11,12,12,11,11,11,11,11,11,11,12,12,11,11,11,11,11,11,11,12,13,13,13,13,13,13,13,3,13,4,6,13,4,4,13,13,13,11,11,11,11,11,11,11,11,11,11,5,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,3,8,3,11,11,11,11,11,11,11,11,11,11,11,5,5,11,11,5,5,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,5,12,3,8,8,3,6,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,10,12,12,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13,13,13,4,13,13,13,4,11,11,11,11,5,11,11,11,11,5,5,11,11,11,11,11,11,11,11,5,5,11,11,11,11,11,11,11,11,8,8,3,3,3,5,10,11,12,12,12,10,10,11,12,12,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,11,11,11,10,11,10,11,11,11,11,10,11,12,10,11,11,11,11,11,10,11,12,12,12,10,11,11,11,10,5,5,5,5,12,5,3,5,11,11,11,10,11,10,11,11,11,11,11,11,11,11,11,11,5,5,5,5,5,5,13,4,13,11,11,11,11,11,11,11,11,11,5,11,11,11,11,5,13,13,3,17,17,17,13,4,13,13,13,13,13,3,4,12,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,0,11,11,11,12,12,11,11,11,11,11,11,12,11,11,11,11,12,11,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,5,3,8,3,5,5,5,5,10,5,5,8,13,4,13,11,11,11,11,11,11,11,11,11,5,5,5,5,11,11,10,11,11,11,11,11,11,11,10,3,11,11,11,5,5,11,11,11,11,11,12,11,12,11,11,11,11,11,3,11,11,12,11,11,11,11,11,11,11,11,7,7,5,5,5,17,17,17,7,17,17,17,17,17,17,17,17,17,17,17,3,3,11,11,11,11,11,5,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,11,11,5,5,8,8,3,10,11,11,11,11,10,11,11,11,11,11,11,11],"n":["Args","Complete","ConversionResult","ConvertLossy","Ignore","InvalidEncodingHandling","Lossy","Panic","accept_any","app","args","args_os","backup_control","borrow","borrow","borrow_mut","borrow_mut","collect_str","collect_str_lossy","coreopts","crash","crash_if_err","encoding","entries","error","execution_phrase","exit","expect_complete","expect_lossy","from","from","fs","fsext","get_utility_is_second_arg","has","into","into","mode","msg_expects_no_more_than_one_of","msg_expects_one_of","msg_invalid_input","msg_invalid_opt_use","msg_opt_invalid_should_be","msg_opt_only_usable_if","os","panic","parse_size","parse_time","perms","process","ranges","return_if_err","ringbuffer","safe_unwrap","safe_write","safe_writeln","set_utility_is_second_arg","show","show_error","show_error_custom_description","show_if_err","show_usage_error","show_warning","signals","snippet_list_join","snippet_list_join_oxford_comma","try_from","try_from","try_into","try_into","type_id","type_id","uio_error","util_name","utmpx","version_cmp","zero_copy","BACKUP_CONTROL_LONG_HELP","BACKUP_CONTROL_VALUES","BackupMode","ExistingBackup","NoBackup","NumberedBackup","SimpleBackup","borrow","borrow_mut","clone","clone_into","determine_backup_mode","determine_backup_suffix","eq","fmt","from","get_backup_path","into","to_owned","try_from","try_into","type_id","CoreOptions","HelpText","borrow","borrow","borrow_mut","borrow_mut","display_usage","from","from","into","into","long_help","name","new","optflag","optflagmulti","optflagopt","optmulti","optopt","parse","summary","syntax","try_from","try_from","try_into","try_into","type_id","type_id","usage","version","Base16","Base2Lsbf","Base2Msbf","Base32","Base32Hex","Base64","Base64Url","Data","Decode","DecodeError","DecodeResult","DecodeZ85","EncodeError","Format","Io","Z85","Z85InputLenNotMultipleOf4","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone_into","decode","decode","encode","encode","fmt","fmt","from","from","from","from","from","from","from","ignore_garbage","into","into","into","into","line_wrap","new","source","to_owned","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","wrap_print","wrap_write","Group","Locate","Passwd","as_inner","as_inner","belongs_to","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","from","from","get_groups","get_groups_gnu","gid","gid","gid2grp","grp2gid","into","into","into_inner","into_inner","locate","locate","locate","locate","locate","name","name","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","uid","uid2usr","user_dir","user_info","user_passwd","user_shell","usr2uid","0","ExitCode","FromIo","UError","UIoError","UResult","USimpleError","UUsageError","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","code","code","code","code","code","code","code","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","get_exit_code","into","into","into","into","map_err_context","message","message","new","new","new","new","set_exit_code","to_string","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","usage","usage","usage","Existing","Logical","Missing","MissingHandling","None","Normal","Physical","ResolveMode","borrow","borrow","borrow_mut","borrow_mut","canonicalize","clone","clone","clone_into","clone_into","display_permissions","display_permissions_unix","eq","eq","fmt","fmt","from","from","into","into","normalize_path","resolve_relative_path","to_owned","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","BirthTime","FsMeta","FsUsage","MountInfo","StatFs","StatFs","avail_blocks","avail_blocks","bavail","bavail_top_bit_set","bfree","birth","block_size","block_size","blocks","blocksize","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","dev_id","dev_name","dummy","eq","f_bavail","f_bavail","f_bfree","f_bfree","f_blocks","f_blocks","f_bsize","f_bsize","f_ffree","f_ffree","f_files","f_files","f_frsize","f_frsize","f_fsid","f_fsid","f_namelen","f_namelen","f_type","f_type","ffree","files","fmt","fmt","fmt","free_blocks","free_blocks","free_file_nodes","free_file_nodes","from","from","from","fs_type","fs_type","fs_type","fsid","fsid","hash","into","into","into","io_size","io_size","mount_dir","mount_option","mount_root","namelen","namelen","ne","new","pretty_birth","pretty_filetype","pretty_fstype","pretty_time","read_fs_list","remote","statfs","statfs_fn","statfs_fn","to_owned","to_owned","to_owned","total_blocks","total_blocks","total_file_nodes","total_file_nodes","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","parse_mode","parse_numeric","parse_symbolic","is_wsl_1","is_wsl_2","mute_sigpipe_panic","ParseFailure","ParseSizeError","SizeTooBig","borrow","borrow_mut","description","eq","fmt","fmt","from","into","ne","parse_size","to_string","try_from","try_into","type_id","from_str","All","Changes","ChownExecutor","FTS_COMFOLLOW","FTS_LOGICAL","FTS_PHYSICAL","Group","IfFrom","Normal","Silent","User","UserGroup","Verbose","Verbosity","VerbosityLevel","bit_flag","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","dereference","dest_gid","dest_uid","entries","eq","eq","exec","files","filter","fmt","fmt","from","from","from","from","groups_only","into","into","into","into","level","ne","preserve_root","recursive","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","verbosity","wrap_chown","Group","Locate","Passwd","get_groups","get_groups_gnu","gid2grp","grp2gid","locate","uid2usr","usr2uid","ChildExt","Code","ExitStatus","Signal","borrow","borrow_mut","clone","clone_into","code","eq","fmt","fmt","from","getegid","geteuid","getgid","getuid","into","ne","send_signal","signal","success","to_owned","to_string","try_from","try_into","type_id","wait_or_timeout","Range","borrow","borrow_mut","cmp","complement","contain","eq","fmt","from","from_list","from_str","high","into","low","ne","partial_cmp","try_from","try_into","type_id","RingBuffer","borrow","borrow_mut","data","from","from_iter","into","new","push_back","try_from","try_into","type_id","ALL_SIGNALS","DEFAULT_SIGNAL","is_signal","signal_by_name_or_value","signal_name_by_value","ACCOUNTING","BOOT_TIME","DEAD_PROCESS","DEFAULT_FILE","EMPTY","INIT_PROCESS","LOGIN_PROCESS","NEW_TIME","OLD_TIME","RUN_LVL","USER_PROCESS","UT_HOSTSIZE","UT_IDSIZE","UT_LINESIZE","UT_NAMESIZE","Utmpx","UtmpxIter","borrow","borrow","borrow_mut","borrow_mut","canon_host","endutxent","exit_status","from","from","getutxent","host","into","into","into_inner","into_iter","is_user_process","iter_all_records","login_time","next","pid","read_from","record_type","setutxent","terminal_suffix","try_from","try_from","try_into","try_into","tty_device","type_id","type_id","user","utmpxname","version_cmp","AsRawObject","FromRawObject","ZeroCopyWriter","as_raw_object","borrow","borrow_mut","flush","from","from_raw_object","into","new","try_from","try_into","type_id","with_default","write"],"q":["uucore","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::backup_control","","","","","","","","","","","","","","","","","","","","","","uucore::coreopts","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::encoding","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::entries","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::error","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::fs","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::fsext","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::mode","","","uucore::os","","uucore::panic","uucore::parse_size","","","","","","","","","","","","","","","","","uucore::parse_time","uucore::perms","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::perms::entries","","","","","","","","","","uucore::process","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::ranges","","","","","","","","","","","","","","","","","","","uucore::ringbuffer","","","","","","","","","","","","uucore::signals","","","","","uucore::utmpx","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","uucore::version_cmp","uucore::zero_copy","","","","","","","","","","","","","","",""],"d":["","","","","","","","","","","","","","","","","","Converts each iterator item to a String and collects …","convenience function for a more slim interface","","Display the provided error message, then exit() with the …","Unwraps the Result. Instead of panicking, it exists the …","","Get password/group file entry","All utils return exit with an exit code. Usually, the …","Derive the complete execution phrase for “usage”.","Calls exit() with the provided exit code.","","","","","","","","","","","","","","","","","","","","","","","","","Unwraps the Result. Instead of panicking, it shows the …","A fixed-size ring buffer.","Unwraps the Result. Instead of panicking, it exists the …","","","","","Show an error to stderr in a similar style to GNU …","Show a warning to stderr in a similar style to GNU …","","Show a bad invocation help message in a similar style to …","","","","","","","","","","","Shorthand to construct [UIoError]-instances.","Derive the utility name.","Aims to provide platform-independent methods to obtain …","","","","","","","","","","","","","","Determine the “mode” for the backup operation to …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Fetch desired entry.","","","","This is a wrapper function for libc::getgrouplist.","","","","","","","","","From: …","The list of group IDs returned from GNU’s groups and GNU…","AKA group.gr_gid","AKA passwd.pw_gid","","","","","","","","","","","","AKA group.gr_name","AKA passwd.pw_name","","","","","","","","AKA passwd.pw_uid","","AKA passwd.pw_dir","AKA passwd.pw_gecos","AKA passwd.pw_passwd","AKA passwd.pw_shell","","","A special error type that does not print any message when …","Enables the conversion from [std::io::Error] to [UError] …","Custom errors defined by the utils and uucore.","Wrapper type around [std::io::Error].","Result type that should be returned by all utils.","A simple error type with an exit code and a message that …","","","","","","","","","","Error code of a custom error.","Error code of a custom error.","","","","","","","","","","","","","","","","","","Get the last exit code set with [set_exit_code]. The …","","","","","","","","","","","","Set the exit code for the program if uumain returns Ok(())…","","","","","","","","","","","","","","","","","Print usage help to a custom error.","Print usage help to a custom error.","","Resolve symbolic links, ignoring errors on the final …","Resolve ‘..’ elements before symlinks","Resolve symbolic links, ignoring errors on the non-final …","Controls how symbolic links should be handled when …","Do not resolve any symbolic links.","Return an error if any part of the path is missing.","Resolve symlinks as encountered when processing the path","Controls when symbolic links are resolved","","","","","Return the canonical, absolute form of a path.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Read file system list.","","","","","","","","","","","","","","","","","","","","","","","","Test if the program is running under WSL","","","","","","","","","","","","","","","Parse a size string into a number of bytes.","","","","","","","","","","","","","","","","","","","","The various level of verbosity","","","","","","","","","","","","","","","","","Get password/group file entry","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Perform the change of owner on a path with the various …","","Fetch desired entry.","","From: …","The list of group IDs returned from GNU’s groups and GNU…","","","","","","Missing methods for Child objects","","","","","","","","","","","","","getegid() returns the effective group ID of the calling …","geteuid() returns the effective user ID of the calling …","getgid() returns the real group ID of the calling process.","getuid() returns the real user ID of the calling process.","","","Send a signal to a Child process.","","","","","","","","Wait for a process to finish or return after the …","","","","","","Test if at least one of the given Ranges contain the …","","","","","","","","","","","","","","A fixed-size ring buffer backed by a VecDeque.","","","","","","","","Append a value to the end of the ring buffer.","","","","","","","","","","","","","","","","","","","","","","","","","Iterator of login records","","","","","Canonicalize host name using DNS","","A.K.A. ut.ut_exit","","","","A.K.A. ut.ut_host","","","Consumes the Utmpx, returning the underlying C struct …","","","","A.K.A. ut.ut_tv","","A.K.A. ut.ut_pid","Sets the name of the utmpx-format file for the other …","A.K.A. ut.ut_type","","A.K.A. ut.ut_id","","","","","A.K.A. ut.ut_line","","","A.K.A. ut.ut_user","","","","","","","","","","","Safety","","","","","","",""],"i":[0,1,0,2,2,0,1,2,1,0,0,0,0,2,1,2,1,3,3,0,0,0,0,0,0,0,0,1,1,2,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,2,1,2,1,0,0,0,0,0,0,0,0,4,4,4,4,4,4,4,4,0,0,4,4,4,0,4,4,4,4,4,0,0,5,6,5,6,5,5,6,5,6,5,5,6,6,6,6,6,6,6,5,5,5,6,5,6,5,6,6,5,7,7,7,7,7,7,7,0,8,0,0,8,0,0,8,7,9,9,10,8,7,9,10,8,7,7,7,0,10,0,10,8,8,9,10,8,8,8,8,7,10,9,10,8,7,10,10,8,7,8,9,10,8,7,9,10,8,7,9,10,8,7,0,0,0,0,0,11,12,12,11,12,11,12,12,12,11,12,0,0,11,12,0,0,11,12,11,12,13,11,11,12,12,11,12,12,11,12,11,12,11,12,12,0,12,12,12,12,0,14,0,0,0,0,0,0,0,15,16,17,14,15,16,17,14,18,18,15,16,14,15,16,15,15,16,16,17,17,14,14,15,16,17,14,0,15,16,17,14,19,15,16,15,16,17,14,0,15,16,17,14,15,16,17,14,15,16,17,14,15,16,17,14,18,18,16,20,21,20,0,21,20,21,0,20,21,20,21,0,20,21,20,21,0,0,20,21,20,21,20,21,20,21,0,0,20,21,20,21,20,21,20,21,0,0,0,0,0,0,22,23,24,24,24,25,22,23,24,24,26,24,23,26,24,23,26,24,23,26,24,23,26,26,26,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,26,24,23,22,23,22,23,26,24,23,22,23,26,22,23,23,26,24,23,22,23,26,26,26,22,23,23,24,25,0,0,0,0,26,0,0,0,26,24,23,22,23,22,23,26,24,23,26,24,23,26,24,23,0,0,0,0,0,0,27,0,27,27,27,27,27,27,27,27,27,27,0,27,27,27,27,0,28,29,0,0,0,0,28,0,29,29,28,28,29,0,0,30,28,30,29,31,28,30,29,31,29,31,29,31,30,30,30,0,29,31,30,30,30,29,31,28,30,29,31,31,28,30,29,31,31,31,30,30,29,31,28,30,29,31,28,30,29,31,28,30,29,31,30,0,0,0,0,0,0,0,0,13,0,0,0,32,0,32,32,32,32,32,32,32,32,32,32,0,0,0,0,32,32,33,32,32,32,32,32,32,32,33,0,34,34,34,0,0,34,34,34,34,34,34,34,34,34,34,34,34,34,0,35,35,35,35,35,35,35,35,35,35,35,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,37,36,37,36,0,36,36,37,0,36,36,37,36,37,36,36,36,37,36,37,36,0,36,36,37,36,37,36,36,37,36,0,0,0,0,0,38,39,39,39,39,40,39,39,39,39,39,39,39],"f":[null,null,null,null,null,null,null,null,[[],[["vec",3],["string",3]]],null,[[]],[[]],null,[[]],[[]],[[]],[[]],[[["invalidencodinghandling",4]],["conversionresult",4]],[[],["conversionresult",4]],null,null,null,null,null,null,[[],["string",3]],null,[[["str",15]],[["vec",3],["string",3]]],[[["str",15]],[["vec",3],["string",3]]],[[]],[[]],null,null,[[],["bool",15]],null,[[]],[[]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],null,null,null,null,null,null,null,null,null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],null,[[],["string",3]],null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[],["backupmode",4]],[[]],[[["bool",15],["str",15],["option",4]],[["string",3],["result",4],["backupmode",4]]],[[["str",15],["option",4]],["string",3]],[[["backupmode",4]],["bool",15]],[[["formatter",3]],["result",6]],[[]],[[["path",3],["str",15],["backupmode",4]],[["pathbuf",3],["option",4]]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],null,null,[[]],[[]],[[]],[[]],null,[[]],[[]],[[]],[[]],null,null,[[["helptext",3]]],[[["str",15]],["coreoptions",3]],[[["str",15]],["coreoptions",3]],[[["str",15]],["coreoptions",3]],[[["str",15]],["coreoptions",3]],[[["str",15]],["coreoptions",3]],[[["vec",3],["string",3]],["matches",3]],null,null,[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[["str",15]],["string",3]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["format",4]],[[]],[[["format",4]],["decoderesult",6]],[[],["decoderesult",6]],[[["format",4]],[["result",4],["string",3],["encodeerror",4]]],[[],[["result",4],["string",3],["encodeerror",4]]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[["error",3]]],[[["decodeerror",4]]],[[["decodeerror",3]]],[[]],[[]],[[["bool",15]]],[[]],[[]],[[]],[[]],[[["usize",15]]],[[["format",4]]],[[],[["error",8],["option",4]]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[["string",3],["data",3]]],[[["write",8],["usize",15],["string",3]],["result",6]],null,null,null,[[],["group",3]],[[],["passwd",3]],[[],[["gid_t",6],["vec",3]]],[[]],[[]],[[]],[[]],[[],["passwd",3]],[[]],[[]],[[]],[[],[["ioresult",6],["vec",3]]],[[["u32",15],["option",4]],[["ioresult",6],["vec",3]]],[[],["gid_t",6]],[[],["gid_t",6]],[[["gid_t",6]],[["string",3],["ioresult",6]]],[[["str",15]],[["gid_t",6],["ioresult",6]]],[[]],[[]],[[],["group",3]],[[],["passwd",3]],[[],["ioresult",6]],[[["str",15]],["ioresult",6]],[[["gid_t",6]],["ioresult",6]],[[["uid_t",6]],["ioresult",6]],[[["str",15]],["ioresult",6]],[[],[["cow",4],["str",15]]],[[],[["cow",4],["str",15]]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["uid_t",6]],[[["uid_t",6]],[["string",3],["ioresult",6]]],[[],[["cow",4],["str",15]]],[[],[["cow",4],["str",15]]],[[],[["cow",4],["str",15]]],[[],[["cow",4],["str",15]]],[[["str",15]],[["uid_t",6],["ioresult",6]]],null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["i32",15]],[[],["i32",15]],[[],["i32",15]],[[],["i32",15]],[[],["i32",15]],null,null,[[["formatter",3]],["result",6]],[[["formatter",3]],[["error",3],["result",4]]],[[["formatter",3]],[["error",3],["result",4]]],[[["formatter",3]],["result",6]],[[["formatter",3]],[["error",3],["result",4]]],[[["formatter",3]],["result",6]],[[["formatter",3]],[["error",3],["result",4]]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[],["i32",15]],[[]],[[]],[[]],[[]],[[]],null,null,[[["string",3],["i32",15],["into",8]],[["uerror",8],["box",3]]],[[["string",3],["i32",15],["into",8]],[["uerror",8],["box",3]]],[[["string",3],["into",8],["errorkind",4]],[["uerror",8],["box",3]]],[[["i32",15]],[["uerror",8],["box",3]]],[[["i32",15]]],[[],["string",3]],[[],["string",3]],[[],["string",3]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["bool",15]],[[],["bool",15]],[[],["bool",15]],null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[["path",3],["asref",8],["missinghandling",4],["resolvemode",4]],[["pathbuf",3],["ioresult",6]]],[[],["missinghandling",4]],[[],["resolvemode",4]],[[]],[[]],[[["bool",15],["metadata",3]],["string",3]],[[["mode_t",6],["bool",15]],["string",3]],[[["missinghandling",4]],["bool",15]],[[["resolvemode",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],[[["path",3]],["pathbuf",3]],[[["path",3]],[["cow",4],["path",3]]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],null,null,null,null,null,[[],["i32",15]],[[],["u64",15]],[[],["u64",15]],null,null,null,[[],["string",3]],[[],["i64",15]],[[],["i64",15]],null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[],["mountinfo",3]],[[],["fsusage",3]],[[],["statfs",3]],[[]],[[]],[[]],null,null,null,[[["statfs",3]],["bool",15]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[["formatter",3]],[["error",3],["result",4]]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[]],[[]],[[]],[[],["i64",15]],[[],["i64",15]],null,[[],["u64",15]],[[],["u64",15]],[[]],[[]],[[]],[[]],[[],["u64",15]],[[],["u64",15]],null,null,null,[[],["u64",15]],[[],["u64",15]],[[["statfs",3]],["bool",15]],[[["statfs",3]],["fsusage",3]],[[],["string",3]],[[["mode_t",6],["u64",15]],["str",15]],[[["i64",15]],[["str",15],["cow",4]]],[[["i64",15]],["string",3]],[[],[["vec",3],["mountinfo",3]]],null,[[["path",3],["asref",8]],[["string",3],["result",4],["statfs",3]]],null,[[],["i32",15]],[[]],[[]],[[]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],["u64",15]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[["str",15]],[["string",3],["result",4],["mode_t",6]]],[[["u32",15],["str",15]],[["result",4],["u32",15],["string",3]]],[[["u32",15],["str",15],["bool",15]],[["result",4],["u32",15],["string",3]]],[[],["bool",15]],[[],["bool",15]],[[]],null,null,null,[[]],[[]],[[],["str",15]],[[["parsesizeerror",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],[["result",4],["error",3]]],[[]],[[]],[[["parsesizeerror",4]],["bool",15]],[[["str",15]],[["result",4],["usize",15],["parsesizeerror",4]]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[["str",15]],[["result",4],["duration",3],["string",3]]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],["verbositylevel",4]],[[],["verbosity",3]],[[]],[[]],null,null,null,null,[[["verbositylevel",4]],["bool",15]],[[["verbosity",3]],["bool",15]],[[],["uresult",6]],null,null,[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[]],[[]],[[]],null,[[]],[[]],[[]],[[]],null,[[["verbosity",3]],["bool",15]],null,null,[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["typeid",3]],null,[[["metadata",3],["bool",15],["path",3],["asref",8],["verbosity",3],["u32",15],["option",4]],[["string",3],["result",4]]],null,null,null,[[],[["ioresult",6],["vec",3]]],[[["u32",15],["option",4]],[["ioresult",6],["vec",3]]],[[["gid_t",6]],[["string",3],["ioresult",6]]],[[["str",15]],[["gid_t",6],["ioresult",6]]],[[],["ioresult",6]],[[["uid_t",6]],[["string",3],["ioresult",6]]],[[["str",15]],[["uid_t",6],["ioresult",6]]],null,null,null,null,[[]],[[]],[[],["exitstatus",4]],[[]],[[],[["option",4],["i32",15]]],[[["exitstatus",4]],["bool",15]],[[["formatter",3]],["result",6]],[[["formatter",3]],["result",6]],[[]],[[],["gid_t",6]],[[],["uid_t",6]],[[],["gid_t",6]],[[],["uid_t",6]],[[]],[[["exitstatus",4]],["bool",15]],[[["usize",15]],["result",6]],[[],[["option",4],["i32",15]]],[[],["bool",15]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[["duration",3]],[["option",4],["result",6]]],null,[[]],[[]],[[["range",3]],["ordering",4]],[[],[["range",3],["vec",3]]],[[["usize",15]],["bool",15]],[[["range",3]],["bool",15]],[[["formatter",3]],["result",6]],[[]],[[["str",15]],[["string",3],["result",4],["vec",3]]],[[["str",15]],[["result",4],["str",15],["range",3]]],null,[[]],null,[[["range",3]],["bool",15]],[[["range",3]],[["option",4],["ordering",4]]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],null,[[]],[[]],null,[[]],[[["usize",15]],["ringbuffer",3]],[[]],[[["usize",15]],["ringbuffer",3]],[[],["option",4]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],null,null,[[["usize",15]],["bool",15]],[[["str",15]],[["usize",15],["option",4]]],[[["usize",15]],[["str",15],["option",4]]],null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,[[]],[[]],[[]],[[]],[[],[["string",3],["ioresult",6]]],[[]],[[]],[[]],[[]],[[]],[[],["string",3]],[[]],[[]],[[],["utmpx",3]],[[]],[[],["bool",15]],[[],["utmpxiter",3]],[[],["tm",3]],[[],["option",4]],[[],["i32",15]],[[["str",15]]],[[],["i16",15]],[[]],[[],["string",3]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["result",4]],[[],["string",3]],[[],["typeid",3]],[[],["typeid",3]],[[],["string",3]],[[],["i32",15]],[[["str",15]],["ordering",4]],null,null,null,[[],["rawfd",6]],[[]],[[]],[[],["result",6]],[[]],[[["rawfd",6]],["option",4]],[[]],[[]],[[],["result",4]],[[],["result",4]],[[],["typeid",3]],[[],["zerocopywriter",3]],[[],[["usize",15],["result",6]]]],"p":[[4,"ConversionResult"],[4,"InvalidEncodingHandling"],[8,"Args"],[4,"BackupMode"],[3,"HelpText"],[3,"CoreOptions"],[4,"Format"],[4,"DecodeError"],[4,"EncodeError"],[3,"Data"],[3,"Group"],[3,"Passwd"],[8,"Locate"],[3,"ExitCode"],[3,"USimpleError"],[3,"UUsageError"],[3,"UIoError"],[8,"UError"],[8,"FromIo"],[4,"MissingHandling"],[4,"ResolveMode"],[8,"FsMeta"],[3,"statfs_fn"],[3,"FsUsage"],[8,"BirthTime"],[3,"MountInfo"],[4,"ParseSizeError"],[4,"IfFrom"],[4,"VerbosityLevel"],[3,"ChownExecutor"],[3,"Verbosity"],[4,"ExitStatus"],[8,"ChildExt"],[3,"Range"],[3,"RingBuffer"],[3,"Utmpx"],[3,"UtmpxIter"],[8,"AsRawObject"],[3,"ZeroCopyWriter"],[8,"FromRawObject"]]},\ +"uucore_procs":{"doc":"","t":[23,14],"n":["gen_uumain","main"],"q":["uucore_procs",""],"d":["",""],"i":[0,0],"f":[null,null],"p":[]},\ +"wc":{"doc":"","t":[5],"n":["main"],"q":["wc"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"who":{"doc":"","t":[5],"n":["main"],"q":["who"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"whoami":{"doc":"","t":[5],"n":["main"],"q":["whoami"],"d":[""],"i":[0],"f":[[[]]],"p":[]},\ +"yes":{"doc":"","t":[5],"n":["main"],"q":["yes"],"d":[""],"i":[0],"f":[[[]]],"p":[]}\ +}'); +if (window.initSearch) {window.initSearch(searchIndex)}; \ No newline at end of file diff --git a/search.js b/search.js new file mode 100644 index 000000000..af0714eed --- /dev/null +++ b/search.js @@ -0,0 +1 @@ +(function(){var itemTypes=["mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","primitive","associatedtype","constant","associatedconstant","union","foreigntype","keyword","existential","attr","derive","traitalias"];var TY_PRIMITIVE=itemTypes.indexOf("primitive");var TY_KEYWORD=itemTypes.indexOf("keyword");function printTab(nb){if(nb===0||nb===1||nb===2){searchState.currentTab=nb}var nb_copy=nb;onEachLazy(document.getElementById("titles").childNodes,function(elem){if(nb_copy===0){addClass(elem,"selected")}else{removeClass(elem,"selected")}nb_copy-=1});onEachLazy(document.getElementById("results").childNodes,function(elem){if(nb===0){addClass(elem,"active")}else{removeClass(elem,"active")}nb-=1})}function removeEmptyStringsFromArray(x){for(var i=0,len=x.length;i-1){var obj=searchIndex[results[i].id];obj.lev=results[i].lev;var res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=obj.displayPath+obj.name;obj.fullPath+="|"+obj.ty;obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out}function sortResults(results,isType){var ar=[];for(var entry in results){if(hasOwnPropertyRustdoc(results,entry)){ar.push(results[entry])}}results=ar;var i,len,result;for(i=0,len=results.length;ib?+1:-1)}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}if((aaa.item.ty===TY_PRIMITIVE&&bbb.item.ty!==TY_KEYWORD)||(aaa.item.ty===TY_KEYWORD&&bbb.item.ty!==TY_PRIMITIVE)){return-1}if((bbb.item.ty===TY_PRIMITIVE&&aaa.item.ty!==TY_PRIMITIVE)||(bbb.item.ty===TY_KEYWORD&&aaa.item.ty!==TY_KEYWORD)){return 1}a=(aaa.item.desc==="");b=(bbb.item.desc==="");if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});for(i=0,len=results.length;i"));return{name:val.substring(0,val.indexOf("<")),generics:values.split(/\s*,\s*/),}}return{name:val,generics:[],}}function getObjectNameFromId(id){if(typeof id==="number"){return searchIndex[id].name}return id}function checkGenerics(obj,val){var tmp_lev,elem_name;if(val.generics.length>0){if(obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>=val.generics.length){var elems=Object.create(null);var elength=obj[GENERICS_DATA].length;for(var x=0;xGENERICS_DATA&&obj[GENERICS_DATA].length>=val.generics.length){var elems=Object.create(null);len=obj[GENERICS_DATA].length;for(x=0;xGENERICS_DATA&&obj[GENERICS_DATA].length!==0){var tmp_lev=checkGenerics(obj,val);if(tmp_lev<=MAX_LEV_DISTANCE){return tmp_lev}}else{return 0}}if(literalSearch){if(obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>0){return obj[GENERICS_DATA].some(function(name){return name===val.name})}return false}lev_distance=Math.min(levenshtein(obj[NAME],val.name),lev_distance);if(lev_distance<=MAX_LEV_DISTANCE){lev_distance=Math.ceil((checkGenerics(obj,val)+lev_distance)/2)}else if(obj.length>GENERICS_DATA&&obj[GENERICS_DATA].length>0){var olength=obj[GENERICS_DATA].length;for(x=0;x0){var length=obj.type[INPUTS_DATA].length;for(var i=0;iOUTPUT_DATA){var ret=obj.type[OUTPUT_DATA];if(typeof ret[0]==="string"){ret=[ret]}for(var x=0,len=ret.length;xlength){return MAX_LEV_DISTANCE+1}for(var i=0;ilength){break}var lev_total=0;var aborted=false;for(var x=0;xMAX_LEV_DISTANCE){aborted=true;break}lev_total+=lev}if(!aborted){ret_lev=Math.min(ret_lev,Math.round(lev_total/clength))}}return ret_lev}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER)return true;if(filter===type)return true;var name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,desc:item.desc,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,}}function handleAliases(ret,query,filterCrates){var aliases=[];var crateAliases=[];if(filterCrates!==undefined){if(ALIASES[filterCrates]&&ALIASES[filterCrates][query.search]){var query_aliases=ALIASES[filterCrates][query.search];var len=query_aliases.length;for(var i=0;iMAX_RESULTS){ret.others.pop()}};onEach(aliases,pushFunc);onEach(crateAliases,pushFunc)}var nSearchWords=searchWords.length;var i,it;var ty;var fullId;var returned;var in_args;var len;if((val.charAt(0)==="\""||val.charAt(0)==="'")&&val.charAt(val.length-1)===val.charAt(0)){val=extractGenerics(val.substr(1,val.length-2));for(i=0;i")>-1){var trimmer=function(s){return s.trim()};var parts=val.split("->").map(trimmer);var input=parts[0];var inputs=input.split(",").map(trimmer).sort();for(i=0,len=inputs.length;i1?paths.length-1:1);var lev,j;for(j=0;j1){lev=checkPath(contains,paths[paths.length-1],ty);if(lev>MAX_LEV_DISTANCE){continue}else if(lev>0){lev_add=lev/10}}returned=MAX_LEV_DISTANCE+1;in_args=MAX_LEV_DISTANCE+1;var index=-1;lev=MAX_LEV_DISTANCE+1;fullId=ty.id;if(searchWords[j].indexOf(split[i])>-1||searchWords[j].indexOf(val)>-1||ty.normalizedName.indexOf(val)>-1){if(typePassesFilter(typeFilter,ty.ty)&&results[fullId]===undefined){index=ty.normalizedName.indexOf(val)}}if((lev=levenshtein(searchWords[j],val))<=MAX_LEV_DISTANCE){if(typePassesFilter(typeFilter,ty.ty)){lev+=1}else{lev=MAX_LEV_DISTANCE+1}}in_args=findArg(ty,valGenerics,false,typeFilter);returned=checkReturned(ty,valGenerics,false,typeFilter);lev+=lev_add;if(lev>0&&val.length>3&&searchWords[j].indexOf(val)>-1){if(val.length<6){lev-=1}else{lev=0}}if(in_args<=MAX_LEV_DISTANCE){if(results_in_args[fullId]===undefined){results_in_args[fullId]={id:j,index:index,lev:in_args,}}results_in_args[fullId].lev=Math.min(results_in_args[fullId].lev,in_args)}if(returned<=MAX_LEV_DISTANCE){if(results_returned[fullId]===undefined){results_returned[fullId]={id:j,index:index,lev:returned,}}results_returned[fullId].lev=Math.min(results_returned[fullId].lev,returned)}if(index!==-1||lev<=MAX_LEV_DISTANCE){if(index!==-1&&paths.length<2){lev=0}if(results[fullId]===undefined){results[fullId]={id:j,index:index,lev:lev,}}results[fullId].lev=Math.min(results[fullId].lev,lev)}}}var ret={"in_args":sortResults(results_in_args,true),"returned":sortResults(results_returned,true),"others":sortResults(results,false),};handleAliases(ret,query,filterCrates);return ret}function validateResult(name,path,keys,parent){for(var i=0,len=keys.length;i-1||path.indexOf(keys[i])>-1||(parent!==undefined&&parent.name!==undefined&&parent.name.toLowerCase().indexOf(keys[i])>-1)||levenshtein(name,keys[i])<=MAX_LEV_DISTANCE)){return false}}return true}function getQuery(raw){var matches,type,query;query=raw;matches=query.match(/^(fn|mod|struct|enum|trait|type|const|macro)\s*:\s*/i);if(matches){type=matches[1].replace(/^const$/,"constant");query=query.substring(matches[0].length)}return{raw:raw,query:query,type:type,id:query+type}}function nextTab(direction){var next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){var target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#titles > button").item(searchState.currentTab);if(target){target.focus()}}function buildHrefAndPath(item){var displayPath;var href;var type=itemTypes[item.ty];var name=item.name;var path=item.path;if(type==="mod"){displayPath=path+"::";href=window.rootPath+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="primitive"||type==="keyword"){displayPath="";href=window.rootPath+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=window.rootPath+name+"/index.html"}else if(item.parent!==undefined){var myparent=item.parent;var anchor="#"+type+"."+name;var parentType=itemTypes[myparent.ty];var pageType=parentType;var pageName=myparent.name;if(parentType==="primitive"){displayPath=myparent.name+"::"}else if(type==="structfield"&&parentType==="variant"){var enumNameIdx=item.path.lastIndexOf("::");var enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="#variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}href=window.rootPath+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html"+anchor}else{displayPath=item.path+"::";href=window.rootPath+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href]}function escape(content){var h1=document.createElement("h1");h1.textContent=content;return h1.innerHTML}function pathSplitter(path){var tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}function addTab(array,query,display){var extraClass="";if(display===true){extraClass=" active"}var output=document.createElement("div");var duplicates={};var length=0;if(array.length>0){output.className="search-results "+extraClass;array.forEach(function(item){if(item.is_alias!==true){if(duplicates[item.fullPath]){return}duplicates[item.fullPath]=true}var name=item.name;var type=itemTypes[item.ty];length+=1;var extra="";if(type==="primitive"){extra=" (primitive type)"}else if(type==="keyword"){extra=" (keyword)"}var link=document.createElement("a");link.className="result-"+type;link.href=item.href;var wrapper=document.createElement("div");var resultName=document.createElement("div");resultName.className="result-name";if(item.is_alias){var alias=document.createElement("span");alias.className="alias";var bold=document.createElement("b");bold.innerText=item.alias;alias.appendChild(bold);alias.insertAdjacentHTML("beforeend"," - see ");resultName.appendChild(alias)}resultName.insertAdjacentHTML("beforeend",item.displayPath+""+name+extra+"");wrapper.appendChild(resultName);var description=document.createElement("div");description.className="desc";var spanDesc=document.createElement("span");spanDesc.insertAdjacentHTML("beforeend",item.desc);description.appendChild(spanDesc);wrapper.appendChild(description);link.appendChild(wrapper);output.appendChild(link)})}else{output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,length]}function makeTabHeader(tabNb,text,nbElems){if(searchState.currentTab===tabNb){return""}return""}function showResults(results){var search=searchState.outputElement();if(results.others.length===1&&getSettingValue("go-to-only-result")==="true"&&(!search.firstChild||search.firstChild.innerText!==searchState.loadingText)){var elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}var query=getQuery(searchState.input.value);currentResults=query.id;var ret_others=addTab(results.others,query);var ret_in_args=addTab(results.in_args,query,false);var ret_returned=addTab(results.returned,query,false);var currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}var output="

Results for "+escape(query.query)+(query.type?" (type: "+escape(query.type)+")":"")+"

"+"
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
";var resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;search.appendChild(resultsElem);searchState.focusedByTab=[null,null,null];searchState.showResults(search);var elems=document.getElementById("titles").childNodes;elems[0].onclick=function(){printTab(0)};elems[1].onclick=function(){printTab(1)};elems[2].onclick=function(){printTab(2)};printTab(currentTab)}function execSearch(query,searchWords,filterCrates){function getSmallest(arrays,positions,notDuplicates){var start=null;for(var it=0,len=positions.length;itpositions[it]&&(start===null||start>arrays[it][positions[it]].lev)&&!notDuplicates[arrays[it][positions[it]].fullPath]){start=arrays[it][positions[it]].lev}}return start}function mergeArrays(arrays){var ret=[];var positions=[];var notDuplicates={};for(var x=0,arrays_len=arrays.length;xpositions[x]&&arrays[x][positions[x]].lev===smallest&&!notDuplicates[arrays[x][positions[x]].fullPath]){ret.push(arrays[x][positions[x]]);notDuplicates[arrays[x][positions[x]].fullPath]=true;positions[x]+=1}}}return ret}var queries=query.raw.split(",");var results={"in_args":[],"returned":[],"others":[],};for(var i=0,len=queries.length;i1){return{"in_args":mergeArrays(results.in_args),"returned":mergeArrays(results.returned),"others":mergeArrays(results.others),}}return{"in_args":results.in_args[0],"returned":results.returned[0],"others":results.others[0],}}function getFilterCrates(){var elem=document.getElementById("crate-search");if(elem&&elem.value!=="All crates"&&hasOwnPropertyRustdoc(rawSearchIndex,elem.value)){return elem.value}return undefined}function search(e,forced){var params=searchState.getQueryStringParams();var query=getQuery(searchState.input.value.trim());if(e){e.preventDefault()}if(query.query.length===0){return}if(!forced&&query.id===currentResults){if(query.query.length>0){searchState.putBackSearch(searchState.input)}return}searchState.title="Results for "+query.query+" - Rust";if(searchState.browserSupportsHistoryApi()){var newURL=getNakedUrl()+"?search="+encodeURIComponent(query.raw)+window.location.hash;if(!history.state&&!params.search){history.pushState(query,"",newURL)}else{history.replaceState(query,"",newURL)}}var filterCrates=getFilterCrates();showResults(execSearch(query,index,filterCrates))}function buildIndex(rawSearchIndex){searchIndex=[];var searchWords=[];var i,word;var currentIndex=0;var id=0;for(var crate in rawSearchIndex){if(!hasOwnPropertyRustdoc(rawSearchIndex,crate)){continue}var crateSize=0;searchWords.push(crate);var crateRow={crate:crate,ty:1,name:crate,path:"",desc:rawSearchIndex[crate].doc,parent:undefined,type:null,id:id,normalizedName:crate.indexOf("_")===-1?crate:crate.replace(/_/g,""),};id+=1;searchIndex.push(crateRow);currentIndex+=1;var itemTypes=rawSearchIndex[crate].t;var itemNames=rawSearchIndex[crate].n;var itemPaths=rawSearchIndex[crate].q;var itemDescs=rawSearchIndex[crate].d;var itemParentIdxs=rawSearchIndex[crate].i;var itemFunctionSearchTypes=rawSearchIndex[crate].f;var paths=rawSearchIndex[crate].p;var aliases=rawSearchIndex[crate].a;var len=paths.length;for(i=0;i0?paths[itemParentIdxs[i]-1]:undefined,type:itemFunctionSearchTypes[i],id:id,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),};id+=1;searchIndex.push(row);lastPath=row.path;crateSize+=1}if(aliases){ALIASES[crate]={};var j,local_aliases;for(var alias_name in aliases){if(!hasOwnPropertyRustdoc(aliases,alias_name)){continue}if(!hasOwnPropertyRustdoc(ALIASES[crate],alias_name)){ALIASES[crate][alias_name]=[]}local_aliases=aliases[alias_name];for(j=0,len=local_aliases.length;j0){searchState.input.value=params.search;search(e)}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=function(){var qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}index=buildIndex(rawSearchIndex);registerSearchEvents();if(searchState.getQueryStringParams().search){search()}};if(window.searchIndex!==undefined){initSearch(window.searchIndex)}})() \ No newline at end of file diff --git a/seq/all.html b/seq/all.html new file mode 100644 index 000000000..24615db22 --- /dev/null +++ b/seq/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/seq/fn.main.html b/seq/fn.main.html new file mode 100644 index 000000000..bdd3e97bc --- /dev/null +++ b/seq/fn.main.html @@ -0,0 +1,3 @@ +main in seq - Rust + +

Function seq::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/seq/index.html b/seq/index.html new file mode 100644 index 000000000..03bfc8116 --- /dev/null +++ b/seq/index.html @@ -0,0 +1,4 @@ +seq - Rust + +

Crate seq[][src]

Functions

+
main
\ No newline at end of file diff --git a/seq/sidebar-items.js b/seq/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/seq/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/settings.css b/settings.css new file mode 100644 index 000000000..670986588 --- /dev/null +++ b/settings.css @@ -0,0 +1 @@ +.setting-line{padding:5px;position:relative;}.setting-line>div{display:inline-block;vertical-align:top;font-size:17px;padding-top:2px;}.setting-line>.title{font-size:19px;width:100%;max-width:none;border-bottom:1px solid;}.toggle{position:relative;display:inline-block;width:45px;height:27px;margin-right:20px;}.toggle input{opacity:0;position:absolute;}.select-wrapper{float:right;position:relative;height:27px;min-width:25%;}.select-wrapper select{appearance:none;-moz-appearance:none;-webkit-appearance:none;background:none;border:2px solid #ccc;padding-right:28px;width:100%;}.select-wrapper img{pointer-events:none;position:absolute;right:0;bottom:0;background:#ccc;height:100%;width:28px;padding:0px 4px;}.select-wrapper select option{color:initial;}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ccc;-webkit-transition:.3s;transition:.3s;}.slider:before{position:absolute;content:"";height:19px;width:19px;left:4px;bottom:4px;background-color:white;-webkit-transition:.3s;transition:.3s;}input:checked+.slider{background-color:#2196F3;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}input:checked+.slider:before{-webkit-transform:translateX(19px);-ms-transform:translateX(19px);transform:translateX(19px);}.setting-line>.sub-settings{padding-left:42px;width:100%;display:block;} \ No newline at end of file diff --git a/settings.html b/settings.html new file mode 100644 index 000000000..e7a110fd1 --- /dev/null +++ b/settings.html @@ -0,0 +1,4 @@ +Rustdoc settings + +

Rustdoc settings

Theme preferences
Use system theme
Preferred dark theme
Preferred light theme
+
Auto-hide item contents for large items.
Auto-hide item methods' documentation
Auto-hide trait implementation documentation
Auto-hide implementors of a trait
Directly go to item in search if there is only one result
Show line numbers on code examples
Disable keyboard shortcuts
\ No newline at end of file diff --git a/settings.js b/settings.js new file mode 100644 index 000000000..b4d6fdcd7 --- /dev/null +++ b/settings.js @@ -0,0 +1 @@ +(function(){function changeSetting(settingName,value){updateLocalStorage("rustdoc-"+settingName,value);switch(settingName){case"preferred-dark-theme":case"preferred-light-theme":case"use-system-theme":updateSystemTheme();break}}function handleKey(ev){if(ev.ctrlKey||ev.altKey||ev.metaKey){return}switch(getVirtualKey(ev)){case"Enter":case"Return":case"Space":ev.target.checked=!ev.target.checked;ev.preventDefault();break}}function setEvents(){onEachLazy(document.getElementsByClassName("slider"),function(elem){var toggle=elem.previousElementSibling;var settingId=toggle.id;var settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=function(){changeSetting(this.id,this.checked)};toggle.onkeyup=handleKey;toggle.onkeyrelease=handleKey});onEachLazy(document.getElementsByClassName("select-wrapper"),function(elem){var select=elem.getElementsByTagName("select")[0];var settingId=select.id;var settingValue=getSettingValue(settingId);if(settingValue!==null){select.value=settingValue}select.onchange=function(){changeSetting(this.id,this.value)}})}window.addEventListener("DOMContentLoaded",setEvents)})() \ No newline at end of file diff --git a/shred/all.html b/shred/all.html new file mode 100644 index 000000000..f86dc9c8b --- /dev/null +++ b/shred/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/shred/fn.main.html b/shred/fn.main.html new file mode 100644 index 000000000..ac773059c --- /dev/null +++ b/shred/fn.main.html @@ -0,0 +1,3 @@ +main in shred - Rust + +

Function shred::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/shred/index.html b/shred/index.html new file mode 100644 index 000000000..4c12365ff --- /dev/null +++ b/shred/index.html @@ -0,0 +1,4 @@ +shred - Rust + +

Crate shred[][src]

Functions

+
main
\ No newline at end of file diff --git a/shred/sidebar-items.js b/shred/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/shred/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/shuf/all.html b/shuf/all.html new file mode 100644 index 000000000..d8af9e677 --- /dev/null +++ b/shuf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/shuf/fn.main.html b/shuf/fn.main.html new file mode 100644 index 000000000..acee53f59 --- /dev/null +++ b/shuf/fn.main.html @@ -0,0 +1,3 @@ +main in shuf - Rust + +

Function shuf::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/shuf/index.html b/shuf/index.html new file mode 100644 index 000000000..0622d06a4 --- /dev/null +++ b/shuf/index.html @@ -0,0 +1,4 @@ +shuf - Rust + +

Crate shuf[][src]

Functions

+
main
\ No newline at end of file diff --git a/shuf/sidebar-items.js b/shuf/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/shuf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/sleep/all.html b/sleep/all.html new file mode 100644 index 000000000..bb12741de --- /dev/null +++ b/sleep/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/sleep/fn.main.html b/sleep/fn.main.html new file mode 100644 index 000000000..1354f7839 --- /dev/null +++ b/sleep/fn.main.html @@ -0,0 +1,3 @@ +main in sleep - Rust + +

Function sleep::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/sleep/index.html b/sleep/index.html new file mode 100644 index 000000000..1d9c0e76f --- /dev/null +++ b/sleep/index.html @@ -0,0 +1,4 @@ +sleep - Rust + +

Crate sleep[][src]

Functions

+
main
\ No newline at end of file diff --git a/sleep/sidebar-items.js b/sleep/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/sleep/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/sort/all.html b/sort/all.html new file mode 100644 index 000000000..64714706c --- /dev/null +++ b/sort/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/sort/fn.main.html b/sort/fn.main.html new file mode 100644 index 000000000..f727ef54c --- /dev/null +++ b/sort/fn.main.html @@ -0,0 +1,3 @@ +main in sort - Rust + +

Function sort::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/sort/index.html b/sort/index.html new file mode 100644 index 000000000..24b3de532 --- /dev/null +++ b/sort/index.html @@ -0,0 +1,4 @@ +sort - Rust + +

Crate sort[][src]

Functions

+
main
\ No newline at end of file diff --git a/sort/sidebar-items.js b/sort/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/sort/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/source-files.js b/source-files.js new file mode 100644 index 000000000..05482983a --- /dev/null +++ b/source-files.js @@ -0,0 +1,206 @@ +var N = null;var sourcesIndex = {}; +sourcesIndex["arch"] = {"name":"","files":["main.rs"]}; +sourcesIndex["base32"] = {"name":"","files":["main.rs"]}; +sourcesIndex["base64"] = {"name":"","files":["main.rs"]}; +sourcesIndex["basename"] = {"name":"","files":["main.rs"]}; +sourcesIndex["basenc"] = {"name":"","files":["main.rs"]}; +sourcesIndex["cat"] = {"name":"","files":["main.rs"]}; +sourcesIndex["chcon"] = {"name":"","files":["main.rs"]}; +sourcesIndex["chgrp"] = {"name":"","files":["main.rs"]}; +sourcesIndex["chmod"] = {"name":"","files":["main.rs"]}; +sourcesIndex["chown"] = {"name":"","files":["main.rs"]}; +sourcesIndex["chroot"] = {"name":"","files":["main.rs"]}; +sourcesIndex["cksum"] = {"name":"","files":["main.rs"]}; +sourcesIndex["comm"] = {"name":"","files":["main.rs"]}; +sourcesIndex["coreutils"] = {"name":"","files":["coreutils.rs"]}; +sourcesIndex["cp"] = {"name":"","files":["main.rs"]}; +sourcesIndex["csplit"] = {"name":"","files":["main.rs"]}; +sourcesIndex["cut"] = {"name":"","files":["main.rs"]}; +sourcesIndex["date"] = {"name":"","files":["main.rs"]}; +sourcesIndex["dd"] = {"name":"","files":["main.rs"]}; +sourcesIndex["df"] = {"name":"","files":["main.rs"]}; +sourcesIndex["dircolors"] = {"name":"","files":["main.rs"]}; +sourcesIndex["dirname"] = {"name":"","files":["main.rs"]}; +sourcesIndex["du"] = {"name":"","files":["main.rs"]}; +sourcesIndex["echo"] = {"name":"","files":["main.rs"]}; +sourcesIndex["env"] = {"name":"","files":["main.rs"]}; +sourcesIndex["expand"] = {"name":"","files":["main.rs"]}; +sourcesIndex["expr"] = {"name":"","files":["main.rs"]}; +sourcesIndex["factor"] = {"name":"","files":["main.rs"]}; +sourcesIndex["false"] = {"name":"","files":["main.rs"]}; +sourcesIndex["fmt"] = {"name":"","files":["main.rs"]}; +sourcesIndex["fold"] = {"name":"","files":["main.rs"]}; +sourcesIndex["groups"] = {"name":"","files":["main.rs"]}; +sourcesIndex["hashsum"] = {"name":"","files":["main.rs"]}; +sourcesIndex["head"] = {"name":"","files":["main.rs"]}; +sourcesIndex["hostid"] = {"name":"","files":["main.rs"]}; +sourcesIndex["hostname"] = {"name":"","files":["main.rs"]}; +sourcesIndex["id"] = {"name":"","files":["main.rs"]}; +sourcesIndex["install"] = {"name":"","files":["main.rs"]}; +sourcesIndex["join"] = {"name":"","files":["main.rs"]}; +sourcesIndex["kill"] = {"name":"","files":["main.rs"]}; +sourcesIndex["libstdbuf"] = {"name":"","files":["libstdbuf.rs"]}; +sourcesIndex["link"] = {"name":"","files":["main.rs"]}; +sourcesIndex["ln"] = {"name":"","files":["main.rs"]}; +sourcesIndex["logname"] = {"name":"","files":["main.rs"]}; +sourcesIndex["ls"] = {"name":"","files":["main.rs"]}; +sourcesIndex["mkdir"] = {"name":"","files":["main.rs"]}; +sourcesIndex["mkfifo"] = {"name":"","files":["main.rs"]}; +sourcesIndex["mknod"] = {"name":"","files":["main.rs"]}; +sourcesIndex["mktemp"] = {"name":"","files":["main.rs"]}; +sourcesIndex["more"] = {"name":"","files":["main.rs"]}; +sourcesIndex["mv"] = {"name":"","files":["main.rs"]}; +sourcesIndex["nice"] = {"name":"","files":["main.rs"]}; +sourcesIndex["nl"] = {"name":"","files":["main.rs"]}; +sourcesIndex["nohup"] = {"name":"","files":["main.rs"]}; +sourcesIndex["nproc"] = {"name":"","files":["main.rs"]}; +sourcesIndex["numfmt"] = {"name":"","files":["main.rs"]}; +sourcesIndex["od"] = {"name":"","files":["main.rs"]}; +sourcesIndex["paste"] = {"name":"","files":["main.rs"]}; +sourcesIndex["pathchk"] = {"name":"","files":["main.rs"]}; +sourcesIndex["pinky"] = {"name":"","files":["main.rs"]}; +sourcesIndex["pr"] = {"name":"","files":["main.rs"]}; +sourcesIndex["printenv"] = {"name":"","files":["main.rs"]}; +sourcesIndex["printf"] = {"name":"","files":["main.rs"]}; +sourcesIndex["ptx"] = {"name":"","files":["main.rs"]}; +sourcesIndex["pwd"] = {"name":"","files":["main.rs"]}; +sourcesIndex["readlink"] = {"name":"","files":["main.rs"]}; +sourcesIndex["realpath"] = {"name":"","files":["main.rs"]}; +sourcesIndex["relpath"] = {"name":"","files":["main.rs"]}; +sourcesIndex["rm"] = {"name":"","files":["main.rs"]}; +sourcesIndex["rmdir"] = {"name":"","files":["main.rs"]}; +sourcesIndex["runcon"] = {"name":"","files":["main.rs"]}; +sourcesIndex["seq"] = {"name":"","files":["main.rs"]}; +sourcesIndex["shred"] = {"name":"","files":["main.rs"]}; +sourcesIndex["shuf"] = {"name":"","files":["main.rs"]}; +sourcesIndex["sleep"] = {"name":"","files":["main.rs"]}; +sourcesIndex["sort"] = {"name":"","files":["main.rs"]}; +sourcesIndex["split"] = {"name":"","files":["main.rs"]}; +sourcesIndex["stat"] = {"name":"","files":["main.rs"]}; +sourcesIndex["stdbuf"] = {"name":"","files":["main.rs"]}; +sourcesIndex["sum"] = {"name":"","files":["main.rs"]}; +sourcesIndex["sync"] = {"name":"","files":["main.rs"]}; +sourcesIndex["tac"] = {"name":"","files":["main.rs"]}; +sourcesIndex["tail"] = {"name":"","files":["main.rs"]}; +sourcesIndex["tee"] = {"name":"","files":["main.rs"]}; +sourcesIndex["test"] = {"name":"","files":["main.rs"]}; +sourcesIndex["timeout"] = {"name":"","files":["main.rs"]}; +sourcesIndex["touch"] = {"name":"","files":["main.rs"]}; +sourcesIndex["tr"] = {"name":"","files":["main.rs"]}; +sourcesIndex["true"] = {"name":"","files":["main.rs"]}; +sourcesIndex["truncate"] = {"name":"","files":["main.rs"]}; +sourcesIndex["tsort"] = {"name":"","files":["main.rs"]}; +sourcesIndex["tty"] = {"name":"","files":["main.rs"]}; +sourcesIndex["uname"] = {"name":"","files":["main.rs"]}; +sourcesIndex["unexpand"] = {"name":"","files":["main.rs"]}; +sourcesIndex["uniq"] = {"name":"","files":["main.rs"]}; +sourcesIndex["unlink"] = {"name":"","files":["main.rs"]}; +sourcesIndex["uptime"] = {"name":"","files":["main.rs"]}; +sourcesIndex["users"] = {"name":"","files":["main.rs"]}; +sourcesIndex["uu_arch"] = {"name":"","files":["arch.rs"]}; +sourcesIndex["uu_base32"] = {"name":"","files":["base32.rs","base_common.rs"]}; +sourcesIndex["uu_base64"] = {"name":"","files":["base64.rs"]}; +sourcesIndex["uu_basename"] = {"name":"","files":["basename.rs"]}; +sourcesIndex["uu_basenc"] = {"name":"","files":["basenc.rs"]}; +sourcesIndex["uu_cat"] = {"name":"","files":["cat.rs","splice.rs"]}; +sourcesIndex["uu_chcon"] = {"name":"","files":["chcon.rs","errors.rs","fts.rs"]}; +sourcesIndex["uu_chgrp"] = {"name":"","files":["chgrp.rs"]}; +sourcesIndex["uu_chmod"] = {"name":"","files":["chmod.rs"]}; +sourcesIndex["uu_chown"] = {"name":"","files":["chown.rs"]}; +sourcesIndex["uu_chroot"] = {"name":"","files":["chroot.rs"]}; +sourcesIndex["uu_cksum"] = {"name":"","files":["cksum.rs"]}; +sourcesIndex["uu_comm"] = {"name":"","files":["comm.rs"]}; +sourcesIndex["uu_cp"] = {"name":"","files":["cp.rs"]}; +sourcesIndex["uu_csplit"] = {"name":"","files":["csplit.rs","csplit_error.rs","patterns.rs","split_name.rs"]}; +sourcesIndex["uu_cut"] = {"name":"","files":["cut.rs","searcher.rs"]}; +sourcesIndex["uu_date"] = {"name":"","files":["date.rs"]}; +sourcesIndex["uu_dd"] = {"name":"","files":["conversion_tables.rs","datastructures.rs","dd.rs","parseargs.rs"]}; +sourcesIndex["uu_df"] = {"name":"","files":["df.rs"]}; +sourcesIndex["uu_dircolors"] = {"name":"","files":["colors.rs","dircolors.rs"]}; +sourcesIndex["uu_dirname"] = {"name":"","files":["dirname.rs"]}; +sourcesIndex["uu_du"] = {"name":"","files":["du.rs"]}; +sourcesIndex["uu_echo"] = {"name":"","files":["echo.rs"]}; +sourcesIndex["uu_env"] = {"name":"","files":["env.rs"]}; +sourcesIndex["uu_expand"] = {"name":"","files":["expand.rs"]}; +sourcesIndex["uu_expr"] = {"name":"","files":["expr.rs","syntax_tree.rs","tokens.rs"]}; +sourcesIndex["uu_factor"] = {"name":"","dirs":[{"name":"numeric","files":["gcd.rs","mod.rs","modular_inverse.rs","montgomery.rs","traits.rs"]}],"files":["cli.rs","factor.rs","miller_rabin.rs","rho.rs","table.rs"]}; +sourcesIndex["uu_false"] = {"name":"","files":["false.rs"]}; +sourcesIndex["uu_fmt"] = {"name":"","files":["fmt.rs","linebreak.rs","parasplit.rs"]}; +sourcesIndex["uu_fold"] = {"name":"","files":["fold.rs"]}; +sourcesIndex["uu_groups"] = {"name":"","files":["groups.rs"]}; +sourcesIndex["uu_hashsum"] = {"name":"","files":["digest.rs","hashsum.rs"]}; +sourcesIndex["uu_head"] = {"name":"","files":["head.rs","lines.rs","parse.rs","split.rs","take.rs"]}; +sourcesIndex["uu_hostid"] = {"name":"","files":["hostid.rs"]}; +sourcesIndex["uu_hostname"] = {"name":"","files":["hostname.rs"]}; +sourcesIndex["uu_id"] = {"name":"","files":["id.rs"]}; +sourcesIndex["uu_install"] = {"name":"","files":["install.rs","mode.rs"]}; +sourcesIndex["uu_join"] = {"name":"","files":["join.rs"]}; +sourcesIndex["uu_kill"] = {"name":"","files":["kill.rs"]}; +sourcesIndex["uu_link"] = {"name":"","files":["link.rs"]}; +sourcesIndex["uu_ln"] = {"name":"","files":["ln.rs"]}; +sourcesIndex["uu_logname"] = {"name":"","files":["logname.rs"]}; +sourcesIndex["uu_ls"] = {"name":"","files":["ls.rs","quoting_style.rs"]}; +sourcesIndex["uu_mkdir"] = {"name":"","files":["mkdir.rs"]}; +sourcesIndex["uu_mkfifo"] = {"name":"","files":["mkfifo.rs"]}; +sourcesIndex["uu_mknod"] = {"name":"","files":["mknod.rs"]}; +sourcesIndex["uu_mktemp"] = {"name":"","files":["mktemp.rs"]}; +sourcesIndex["uu_more"] = {"name":"","files":["more.rs"]}; +sourcesIndex["uu_mv"] = {"name":"","files":["mv.rs"]}; +sourcesIndex["uu_nice"] = {"name":"","files":["nice.rs"]}; +sourcesIndex["uu_nl"] = {"name":"","files":["helper.rs","nl.rs"]}; +sourcesIndex["uu_nohup"] = {"name":"","files":["nohup.rs"]}; +sourcesIndex["uu_nproc"] = {"name":"","files":["nproc.rs"]}; +sourcesIndex["uu_numfmt"] = {"name":"","files":["format.rs","numfmt.rs","options.rs","units.rs"]}; +sourcesIndex["uu_od"] = {"name":"","files":["byteorder_io.rs","formatteriteminfo.rs","inputdecoder.rs","inputoffset.rs","multifilereader.rs","od.rs","output_info.rs","parse_formats.rs","parse_inputs.rs","parse_nrofbytes.rs","partialreader.rs","peekreader.rs","prn_char.rs","prn_float.rs","prn_int.rs"]}; +sourcesIndex["uu_paste"] = {"name":"","files":["paste.rs"]}; +sourcesIndex["uu_pathchk"] = {"name":"","files":["pathchk.rs"]}; +sourcesIndex["uu_pinky"] = {"name":"","files":["pinky.rs"]}; +sourcesIndex["uu_pr"] = {"name":"","files":["pr.rs"]}; +sourcesIndex["uu_printenv"] = {"name":"","files":["printenv.rs"]}; +sourcesIndex["uu_printf"] = {"name":"","dirs":[{"name":"tokenize","dirs":[{"name":"num_format","dirs":[{"name":"formatters","dirs":[{"name":"base_conv","files":["mod.rs","tests.rs"]}],"files":["cninetyninehexfloatf.rs","decf.rs","float_common.rs","floatf.rs","intf.rs","mod.rs","scif.rs"]}],"files":["format_field.rs","formatter.rs","mod.rs","num_format.rs"]}],"files":["mod.rs","sub.rs","token.rs","unescaped_text.rs"]}],"files":["cli.rs","memo.rs","printf.rs"]}; +sourcesIndex["uu_ptx"] = {"name":"","files":["ptx.rs"]}; +sourcesIndex["uu_pwd"] = {"name":"","files":["pwd.rs"]}; +sourcesIndex["uu_readlink"] = {"name":"","files":["readlink.rs"]}; +sourcesIndex["uu_realpath"] = {"name":"","files":["realpath.rs"]}; +sourcesIndex["uu_relpath"] = {"name":"","files":["relpath.rs"]}; +sourcesIndex["uu_rm"] = {"name":"","files":["rm.rs"]}; +sourcesIndex["uu_rmdir"] = {"name":"","files":["rmdir.rs"]}; +sourcesIndex["uu_runcon"] = {"name":"","files":["errors.rs","runcon.rs"]}; +sourcesIndex["uu_seq"] = {"name":"","files":["seq.rs"]}; +sourcesIndex["uu_shred"] = {"name":"","files":["shred.rs"]}; +sourcesIndex["uu_shuf"] = {"name":"","files":["shuf.rs"]}; +sourcesIndex["uu_sleep"] = {"name":"","files":["sleep.rs"]}; +sourcesIndex["uu_sort"] = {"name":"","files":["check.rs","chunks.rs","custom_str_cmp.rs","ext_sort.rs","merge.rs","numeric_str_cmp.rs","sort.rs","tmp_dir.rs"]}; +sourcesIndex["uu_split"] = {"name":"","dirs":[{"name":"platform","files":["mod.rs","unix.rs"]}],"files":["split.rs"]}; +sourcesIndex["uu_stat"] = {"name":"","files":["stat.rs"]}; +sourcesIndex["uu_stdbuf"] = {"name":"","files":["stdbuf.rs"]}; +sourcesIndex["uu_sum"] = {"name":"","files":["sum.rs"]}; +sourcesIndex["uu_sync"] = {"name":"","files":["sync.rs"]}; +sourcesIndex["uu_tac"] = {"name":"","files":["tac.rs"]}; +sourcesIndex["uu_tail"] = {"name":"","dirs":[{"name":"platform","files":["mod.rs","unix.rs"]}],"files":["chunks.rs","tail.rs"]}; +sourcesIndex["uu_tee"] = {"name":"","files":["tee.rs"]}; +sourcesIndex["uu_test"] = {"name":"","files":["parser.rs","test.rs"]}; +sourcesIndex["uu_timeout"] = {"name":"","files":["timeout.rs"]}; +sourcesIndex["uu_touch"] = {"name":"","files":["touch.rs"]}; +sourcesIndex["uu_tr"] = {"name":"","files":["expand.rs","tr.rs"]}; +sourcesIndex["uu_true"] = {"name":"","files":["true.rs"]}; +sourcesIndex["uu_truncate"] = {"name":"","files":["truncate.rs"]}; +sourcesIndex["uu_tsort"] = {"name":"","files":["tsort.rs"]}; +sourcesIndex["uu_tty"] = {"name":"","files":["tty.rs"]}; +sourcesIndex["uu_uname"] = {"name":"","files":["uname.rs"]}; +sourcesIndex["uu_unexpand"] = {"name":"","files":["unexpand.rs"]}; +sourcesIndex["uu_uniq"] = {"name":"","files":["uniq.rs"]}; +sourcesIndex["uu_unlink"] = {"name":"","files":["unlink.rs"]}; +sourcesIndex["uu_uptime"] = {"name":"","files":["uptime.rs"]}; +sourcesIndex["uu_users"] = {"name":"","files":["users.rs"]}; +sourcesIndex["uu_wc"] = {"name":"","files":["count_bytes.rs","countable.rs","wc.rs","word_count.rs"]}; +sourcesIndex["uu_who"] = {"name":"","files":["who.rs"]}; +sourcesIndex["uu_whoami"] = {"name":"","dirs":[{"name":"platform","files":["mod.rs","unix.rs"]}],"files":["whoami.rs"]}; +sourcesIndex["uu_yes"] = {"name":"","files":["yes.rs"]}; +sourcesIndex["uucore"] = {"name":"","dirs":[{"name":"features","dirs":[{"name":"zero_copy","dirs":[{"name":"platform","files":["linux.rs","unix.rs"]}],"files":["platform.rs"]}],"files":["encoding.rs","entries.rs","fs.rs","fsext.rs","mode.rs","perms.rs","process.rs","ringbuffer.rs","signals.rs","utmpx.rs","zero_copy.rs"]},{"name":"mods","files":["backup_control.rs","coreopts.rs","error.rs","os.rs","panic.rs","ranges.rs","version_cmp.rs"]},{"name":"parser","files":["parse_size.rs","parse_time.rs"]}],"files":["features.rs","lib.rs","macros.rs","mods.rs","parser.rs"]}; +sourcesIndex["uucore_procs"] = {"name":"","files":["lib.rs"]}; +sourcesIndex["wc"] = {"name":"","files":["main.rs"]}; +sourcesIndex["who"] = {"name":"","files":["main.rs"]}; +sourcesIndex["whoami"] = {"name":"","files":["main.rs"]}; +sourcesIndex["yes"] = {"name":"","files":["main.rs"]}; +createSourceSidebar(); diff --git a/source-script.js b/source-script.js new file mode 100644 index 000000000..5dc8fee0f --- /dev/null +++ b/source-script.js @@ -0,0 +1 @@ +(function(){function getCurrentFilePath(){var parts=window.location.pathname.split("/");var rootPathParts=window.rootPath.split("/");for(var i=0,len=rootPathParts.length;i"){sidebar.style.left="";this.style.left="";child.innerText="<";updateLocalStorage("rustdoc-source-sidebar-show","true")}else{sidebar.style.left="-300px";this.style.left="0";child.innerText=">";updateLocalStorage("rustdoc-source-sidebar-show","false")}}function createSidebarToggle(){var sidebarToggle=document.createElement("div");sidebarToggle.id="sidebar-toggle";sidebarToggle.onclick=toggleSidebar;var inner1=document.createElement("div");inner1.style.position="relative";var inner2=document.createElement("div");inner2.style.paddingTop="3px";if(getCurrentValue("rustdoc-source-sidebar-show")==="true"){inner2.innerText="<"}else{inner2.innerText=">";sidebarToggle.style.left="0"}inner1.appendChild(inner2);sidebarToggle.appendChild(inner1);return sidebarToggle}function createSourceSidebar(){if(!window.rootPath.endsWith("/")){window.rootPath+="/"}var main=document.getElementById("main");var sidebarToggle=createSidebarToggle();main.insertBefore(sidebarToggle,main.firstChild);var sidebar=document.createElement("div");sidebar.id="source-sidebar";if(getCurrentValue("rustdoc-source-sidebar-show")!=="true"){sidebar.style.left="-300px"}var currentFile=getCurrentFilePath();var hasFoundFile=false;var title=document.createElement("div");title.className="title";title.innerText="Files";sidebar.appendChild(title);Object.keys(sourcesIndex).forEach(function(key){sourcesIndex[key].name=key;hasFoundFile=createDirEntry(sourcesIndex[key],sidebar,"",currentFile,hasFoundFile)});main.insertBefore(sidebar,main.firstChild);var selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}var lineNumbersRegex=/^#?(\d+)(?:-(\d+))?$/;function highlightSourceLines(scrollTo,match){if(typeof match==="undefined"){match=window.location.hash.match(lineNumbersRegex)}if(!match){return}var from=parseInt(match[1],10);var to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(tocur_line_id){var tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());window.addEventListener("hashchange",function(){var match=window.location.hash.match(lineNumbersRegex);if(match){return highlightSourceLines(false,match)}});onEachLazy(document.getElementsByClassName("line-numbers"),function(el){el.addEventListener("click",handleSourceHighlight)});highlightSourceLines(true);window.createSourceSidebar=createSourceSidebar})() \ No newline at end of file diff --git a/split/all.html b/split/all.html new file mode 100644 index 000000000..cc520036f --- /dev/null +++ b/split/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/split/fn.main.html b/split/fn.main.html new file mode 100644 index 000000000..c30f84f4b --- /dev/null +++ b/split/fn.main.html @@ -0,0 +1,3 @@ +main in split - Rust + +

Function split::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/split/index.html b/split/index.html new file mode 100644 index 000000000..4e32c3407 --- /dev/null +++ b/split/index.html @@ -0,0 +1,4 @@ +split - Rust + +

Crate split[][src]

Functions

+
main
\ No newline at end of file diff --git a/split/sidebar-items.js b/split/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/split/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/src/arch/main.rs.html b/src/arch/main.rs.html new file mode 100644 index 000000000..7eada39dc --- /dev/null +++ b/src/arch/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_arch);
+
+
\ No newline at end of file diff --git a/src/base32/main.rs.html b/src/base32/main.rs.html new file mode 100644 index 000000000..92200f832 --- /dev/null +++ b/src/base32/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_base32);
+
+
\ No newline at end of file diff --git a/src/base64/main.rs.html b/src/base64/main.rs.html new file mode 100644 index 000000000..79f9657c8 --- /dev/null +++ b/src/base64/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_base64);
+
+
\ No newline at end of file diff --git a/src/basename/main.rs.html b/src/basename/main.rs.html new file mode 100644 index 000000000..09c047548 --- /dev/null +++ b/src/basename/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_basename);
+
+
\ No newline at end of file diff --git a/src/basenc/main.rs.html b/src/basenc/main.rs.html new file mode 100644 index 000000000..518a2a690 --- /dev/null +++ b/src/basenc/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_basenc);
+
+
\ No newline at end of file diff --git a/src/cat/main.rs.html b/src/cat/main.rs.html new file mode 100644 index 000000000..aeb7b29a9 --- /dev/null +++ b/src/cat/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_cat);
+
+
\ No newline at end of file diff --git a/src/chcon/main.rs.html b/src/chcon/main.rs.html new file mode 100644 index 000000000..63e6c6a05 --- /dev/null +++ b/src/chcon/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_chcon);
+
+
\ No newline at end of file diff --git a/src/chgrp/main.rs.html b/src/chgrp/main.rs.html new file mode 100644 index 000000000..2a5ee24d4 --- /dev/null +++ b/src/chgrp/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_chgrp);
+
+
\ No newline at end of file diff --git a/src/chmod/main.rs.html b/src/chmod/main.rs.html new file mode 100644 index 000000000..3d06e42e0 --- /dev/null +++ b/src/chmod/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_chmod);
+
+
\ No newline at end of file diff --git a/src/chown/main.rs.html b/src/chown/main.rs.html new file mode 100644 index 000000000..31d48185f --- /dev/null +++ b/src/chown/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_chown);
+
+
\ No newline at end of file diff --git a/src/chroot/main.rs.html b/src/chroot/main.rs.html new file mode 100644 index 000000000..4a1d8b5c4 --- /dev/null +++ b/src/chroot/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_chroot);
+
+
\ No newline at end of file diff --git a/src/cksum/main.rs.html b/src/cksum/main.rs.html new file mode 100644 index 000000000..d262d3c2b --- /dev/null +++ b/src/cksum/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_cksum);
+
+
\ No newline at end of file diff --git a/src/comm/main.rs.html b/src/comm/main.rs.html new file mode 100644 index 000000000..c2f10bd51 --- /dev/null +++ b/src/comm/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_comm);
+
+
\ No newline at end of file diff --git a/src/coreutils/coreutils.rs.html b/src/coreutils/coreutils.rs.html new file mode 100644 index 000000000..b459b54f1 --- /dev/null +++ b/src/coreutils/coreutils.rs.html @@ -0,0 +1,345 @@ +coreutils.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Michael Gehring <mg@ebfe.org>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use clap::App;
+use clap::Arg;
+use clap::Shell;
+use std::cmp;
+use std::collections::hash_map::HashMap;
+use std::ffi::OsString;
+use std::io::{self, Write};
+use std::path::{Path, PathBuf};
+use std::process;
+
+const VERSION: &str = env!("CARGO_PKG_VERSION");
+
+include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));
+
+fn usage<T>(utils: &UtilityMap<T>, name: &str) {
+    println!("{} {} (multi-call binary)\n", name, VERSION);
+    println!("Usage: {} [function [arguments...]]\n", name);
+    println!("Currently defined functions:\n");
+    #[allow(clippy::map_clone)]
+    let mut utils: Vec<&str> = utils.keys().map(|&s| s).collect();
+    utils.sort_unstable();
+    let display_list = utils.join(", ");
+    let width = cmp::min(textwrap::termwidth(), 100) - 4 * 2; // (opinion/heuristic) max 100 chars wide with 4 character side indentions
+    println!(
+        "{}",
+        textwrap::indent(&textwrap::fill(&display_list, width), "    ")
+    );
+}
+
+fn binary_path(args: &mut impl Iterator<Item = OsString>) -> PathBuf {
+    match args.next() {
+        Some(ref s) if !s.is_empty() => PathBuf::from(s),
+        _ => std::env::current_exe().unwrap(),
+    }
+}
+
+fn name(binary_path: &Path) -> &str {
+    binary_path.file_stem().unwrap().to_str().unwrap()
+}
+
+fn main() {
+    uucore::panic::mute_sigpipe_panic();
+
+    let utils = util_map();
+    let mut args = uucore::args_os();
+
+    let binary = binary_path(&mut args);
+    let binary_as_util = name(&binary);
+
+    // binary name equals util name?
+    if let Some(&(uumain, _)) = utils.get(binary_as_util) {
+        process::exit(uumain((vec![binary.into()].into_iter()).chain(args)));
+    }
+
+    // binary name equals prefixed util name?
+    // * prefix/stem may be any string ending in a non-alphanumeric character
+    let util_name = if let Some(util) = utils.keys().find(|util| {
+        binary_as_util.ends_with(*util)
+            && !(&binary_as_util[..binary_as_util.len() - (*util).len()])
+                .ends_with(char::is_alphanumeric)
+    }) {
+        // prefixed util => replace 0th (aka, executable name) argument
+        Some(OsString::from(*util))
+    } else {
+        // unmatched binary name => regard as multi-binary container and advance argument list
+        uucore::set_utility_is_second_arg();
+        args.next()
+    };
+
+    // 0th argument equals util name?
+    if let Some(util_os) = util_name {
+        let util = util_os.as_os_str().to_string_lossy();
+
+        if util == "completion" {
+            gen_completions(args, utils);
+        }
+
+        match utils.get(&util[..]) {
+            Some(&(uumain, _)) => {
+                process::exit(uumain((vec![util_os].into_iter()).chain(args)));
+            }
+            None => {
+                if util == "--help" || util == "-h" {
+                    // see if they want help on a specific util
+                    if let Some(util_os) = args.next() {
+                        let util = util_os.as_os_str().to_string_lossy();
+
+                        match utils.get(&util[..]) {
+                            Some(&(uumain, _)) => {
+                                let code = uumain(
+                                    (vec![util_os, OsString::from("--help")].into_iter())
+                                        .chain(args),
+                                );
+                                io::stdout().flush().expect("could not flush stdout");
+                                process::exit(code);
+                            }
+                            None => {
+                                println!("{}: function/utility not found", util);
+                                process::exit(1);
+                            }
+                        }
+                    }
+                    usage(&utils, binary_as_util);
+                    process::exit(0);
+                } else {
+                    println!("{}: function/utility not found", util);
+                    process::exit(1);
+                }
+            }
+        }
+    } else {
+        // no arguments provided
+        usage(&utils, binary_as_util);
+        process::exit(0);
+    }
+}
+
+/// Prints completions for the utility in the first parameter for the shell in the second parameter to stdout
+fn gen_completions<T: uucore::Args>(
+    args: impl Iterator<Item = OsString>,
+    util_map: UtilityMap<T>,
+) -> ! {
+    let all_utilities: Vec<_> = std::iter::once("coreutils")
+        .chain(util_map.keys().copied())
+        .collect();
+
+    let matches = App::new("completion")
+        .about("Prints completions to stdout")
+        .arg(
+            Arg::with_name("utility")
+                .possible_values(&all_utilities)
+                .required(true),
+        )
+        .arg(
+            Arg::with_name("shell")
+                .possible_values(&Shell::variants())
+                .required(true),
+        )
+        .get_matches_from(std::iter::once(OsString::from("completion")).chain(args));
+
+    let utility = matches.value_of("utility").unwrap();
+    let shell = matches.value_of("shell").unwrap();
+
+    let mut app = if utility == "coreutils" {
+        gen_coreutils_app(util_map)
+    } else {
+        util_map.get(utility).unwrap().1()
+    };
+    let shell: Shell = shell.parse().unwrap();
+    let bin_name = std::env::var("PROG_PREFIX").unwrap_or_default() + utility;
+
+    app.gen_completions_to(bin_name, shell, &mut io::stdout());
+    io::stdout().flush().unwrap();
+    process::exit(0);
+}
+
+fn gen_coreutils_app<T: uucore::Args>(util_map: UtilityMap<T>) -> App<'static, 'static> {
+    let mut app = App::new("coreutils");
+    for (_, (_, sub_app)) in util_map {
+        app = app.subcommand(sub_app());
+    }
+    app
+}
+
+
\ No newline at end of file diff --git a/src/coreutils/home/runner/work/coreutils-docs/coreutils-docs/coreutils/target/debug/build/coreutils-cefdaf49d9a50b37/out/uutils_map.rs.html b/src/coreutils/home/runner/work/coreutils-docs/coreutils-docs/coreutils/target/debug/build/coreutils-cefdaf49d9a50b37/out/uutils_map.rs.html new file mode 100644 index 000000000..3990314fd --- /dev/null +++ b/src/coreutils/home/runner/work/coreutils-docs/coreutils-docs/coreutils/target/debug/build/coreutils-cefdaf49d9a50b37/out/uutils_map.rs.html @@ -0,0 +1,245 @@ +uutils_map.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+
+type UtilityMap<T> = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static, 'static>)>;
+
+fn util_map<T: uucore::Args>() -> UtilityMap<T> {
+	let mut map = UtilityMap::new();
+	map.insert("arch", (arch::uumain, arch::uu_app));
+	map.insert("base32", (base32::uumain, base32::uu_app));
+	map.insert("base64", (base64::uumain, base64::uu_app));
+	map.insert("basename", (basename::uumain, basename::uu_app));
+	map.insert("basenc", (basenc::uumain, basenc::uu_app));
+	map.insert("cat", (cat::uumain, cat::uu_app));
+	map.insert("chcon", (chcon::uumain, chcon::uu_app));
+	map.insert("chgrp", (chgrp::uumain, chgrp::uu_app));
+	map.insert("chmod", (chmod::uumain, chmod::uu_app));
+	map.insert("chown", (chown::uumain, chown::uu_app));
+	map.insert("chroot", (chroot::uumain, chroot::uu_app));
+	map.insert("cksum", (cksum::uumain, cksum::uu_app));
+	map.insert("comm", (comm::uumain, comm::uu_app));
+	map.insert("cp", (cp::uumain, cp::uu_app));
+	map.insert("csplit", (csplit::uumain, csplit::uu_app));
+	map.insert("cut", (cut::uumain, cut::uu_app));
+	map.insert("date", (date::uumain, date::uu_app));
+	map.insert("dd", (dd::uumain, dd::uu_app));
+	map.insert("df", (df::uumain, df::uu_app));
+	map.insert("dircolors", (dircolors::uumain, dircolors::uu_app));
+	map.insert("dirname", (dirname::uumain, dirname::uu_app));
+	map.insert("du", (du::uumain, du::uu_app));
+	map.insert("echo", (echo::uumain, echo::uu_app));
+	map.insert("env", (env::uumain, env::uu_app));
+	map.insert("expand", (expand::uumain, expand::uu_app));
+	map.insert("expr", (expr::uumain, expr::uu_app));
+	map.insert("factor", (factor::uumain, factor::uu_app));
+	map.insert("false", (r#false::uumain, r#false::uu_app));
+	map.insert("fmt", (fmt::uumain, fmt::uu_app));
+	map.insert("fold", (fold::uumain, fold::uu_app));
+	map.insert("groups", (groups::uumain, groups::uu_app));
+	map.insert("hashsum", (hashsum::uumain, hashsum::uu_app_custom));
+		map.insert("md5sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha1sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha224sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha256sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha384sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha512sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha3sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha3-224sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha3-256sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha3-384sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("sha3-512sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("shake128sum", (hashsum::uumain, hashsum::uu_app_common));
+		map.insert("shake256sum", (hashsum::uumain, hashsum::uu_app_common));
+	map.insert("head", (head::uumain, head::uu_app));
+	map.insert("hostid", (hostid::uumain, hostid::uu_app));
+	map.insert("hostname", (hostname::uumain, hostname::uu_app));
+	map.insert("id", (id::uumain, id::uu_app));
+	map.insert("install", (install::uumain, install::uu_app));
+	map.insert("join", (join::uumain, join::uu_app));
+	map.insert("kill", (kill::uumain, kill::uu_app));
+	map.insert("link", (link::uumain, link::uu_app));
+	map.insert("ln", (ln::uumain, ln::uu_app));
+	map.insert("logname", (logname::uumain, logname::uu_app));
+	map.insert("ls", (ls::uumain, ls::uu_app));
+	map.insert("mkdir", (mkdir::uumain, mkdir::uu_app));
+	map.insert("mkfifo", (mkfifo::uumain, mkfifo::uu_app));
+	map.insert("mknod", (mknod::uumain, mknod::uu_app));
+	map.insert("mktemp", (mktemp::uumain, mktemp::uu_app));
+	map.insert("more", (more::uumain, more::uu_app));
+	map.insert("mv", (mv::uumain, mv::uu_app));
+	map.insert("nice", (nice::uumain, nice::uu_app));
+	map.insert("nl", (nl::uumain, nl::uu_app));
+	map.insert("nohup", (nohup::uumain, nohup::uu_app));
+	map.insert("nproc", (nproc::uumain, nproc::uu_app));
+	map.insert("numfmt", (numfmt::uumain, numfmt::uu_app));
+	map.insert("od", (od::uumain, od::uu_app));
+	map.insert("paste", (paste::uumain, paste::uu_app));
+	map.insert("pathchk", (pathchk::uumain, pathchk::uu_app));
+	map.insert("pinky", (pinky::uumain, pinky::uu_app));
+	map.insert("pr", (pr::uumain, pr::uu_app));
+	map.insert("printenv", (printenv::uumain, printenv::uu_app));
+	map.insert("printf", (printf::uumain, printf::uu_app));
+	map.insert("ptx", (ptx::uumain, ptx::uu_app));
+	map.insert("pwd", (pwd::uumain, pwd::uu_app));
+	map.insert("readlink", (readlink::uumain, readlink::uu_app));
+	map.insert("realpath", (realpath::uumain, realpath::uu_app));
+	map.insert("relpath", (relpath::uumain, relpath::uu_app));
+	map.insert("rm", (rm::uumain, rm::uu_app));
+	map.insert("rmdir", (rmdir::uumain, rmdir::uu_app));
+	map.insert("runcon", (runcon::uumain, runcon::uu_app));
+	map.insert("seq", (seq::uumain, seq::uu_app));
+	map.insert("shred", (shred::uumain, shred::uu_app));
+	map.insert("shuf", (shuf::uumain, shuf::uu_app));
+	map.insert("sleep", (sleep::uumain, sleep::uu_app));
+	map.insert("sort", (sort::uumain, sort::uu_app));
+	map.insert("split", (split::uumain, split::uu_app));
+	map.insert("stat", (stat::uumain, stat::uu_app));
+	map.insert("stdbuf", (stdbuf::uumain, stdbuf::uu_app));
+	map.insert("sum", (sum::uumain, sum::uu_app));
+	map.insert("sync", (sync::uumain, sync::uu_app));
+	map.insert("tac", (tac::uumain, tac::uu_app));
+	map.insert("tail", (tail::uumain, tail::uu_app));
+	map.insert("tee", (tee::uumain, tee::uu_app));
+	map.insert("timeout", (timeout::uumain, timeout::uu_app));
+	map.insert("touch", (touch::uumain, touch::uu_app));
+	map.insert("tr", (tr::uumain, tr::uu_app));
+	map.insert("true", (r#true::uumain, r#true::uu_app));
+	map.insert("truncate", (truncate::uumain, truncate::uu_app));
+	map.insert("tsort", (tsort::uumain, tsort::uu_app));
+	map.insert("tty", (tty::uumain, tty::uu_app));
+	map.insert("uname", (uname::uumain, uname::uu_app));
+	map.insert("unexpand", (unexpand::uumain, unexpand::uu_app));
+	map.insert("uniq", (uniq::uumain, uniq::uu_app));
+	map.insert("unlink", (unlink::uumain, unlink::uu_app));
+	map.insert("uptime", (uptime::uumain, uptime::uu_app));
+	map.insert("users", (users::uumain, users::uu_app));
+	map.insert("test", (uu_test::uumain, uu_test::uu_app));
+		map.insert("[", (uu_test::uumain, uu_test::uu_app));
+	map.insert("wc", (wc::uumain, wc::uu_app));
+	map.insert("who", (who::uumain, who::uu_app));
+	map.insert("whoami", (whoami::uumain, whoami::uu_app));
+	map.insert("yes", (yes::uumain, yes::uu_app));
+map
+}
+
+
\ No newline at end of file diff --git a/src/cp/main.rs.html b/src/cp/main.rs.html new file mode 100644 index 000000000..a8828e89c --- /dev/null +++ b/src/cp/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_cp);
+
+
\ No newline at end of file diff --git a/src/csplit/main.rs.html b/src/csplit/main.rs.html new file mode 100644 index 000000000..34f29f333 --- /dev/null +++ b/src/csplit/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_csplit);
+
+
\ No newline at end of file diff --git a/src/cut/main.rs.html b/src/cut/main.rs.html new file mode 100644 index 000000000..7103e28aa --- /dev/null +++ b/src/cut/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_cut);
+
+
\ No newline at end of file diff --git a/src/date/main.rs.html b/src/date/main.rs.html new file mode 100644 index 000000000..5b74c03fa --- /dev/null +++ b/src/date/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_date);
+
+
\ No newline at end of file diff --git a/src/dd/main.rs.html b/src/dd/main.rs.html new file mode 100644 index 000000000..b3967552f --- /dev/null +++ b/src/dd/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_dd); // spell-checker:ignore procs uucore
+
+
\ No newline at end of file diff --git a/src/df/main.rs.html b/src/df/main.rs.html new file mode 100644 index 000000000..06db3369d --- /dev/null +++ b/src/df/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_df);
+
+
\ No newline at end of file diff --git a/src/dircolors/main.rs.html b/src/dircolors/main.rs.html new file mode 100644 index 000000000..43c5b53d6 --- /dev/null +++ b/src/dircolors/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_dircolors);
+
+
\ No newline at end of file diff --git a/src/dirname/main.rs.html b/src/dirname/main.rs.html new file mode 100644 index 000000000..c9c899bed --- /dev/null +++ b/src/dirname/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_dirname);
+
+
\ No newline at end of file diff --git a/src/du/main.rs.html b/src/du/main.rs.html new file mode 100644 index 000000000..9d64f1b03 --- /dev/null +++ b/src/du/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_du);
+
+
\ No newline at end of file diff --git a/src/echo/main.rs.html b/src/echo/main.rs.html new file mode 100644 index 000000000..a4535835d --- /dev/null +++ b/src/echo/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_echo);
+
+
\ No newline at end of file diff --git a/src/env/main.rs.html b/src/env/main.rs.html new file mode 100644 index 000000000..0e8348e8d --- /dev/null +++ b/src/env/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_env);
+
+
\ No newline at end of file diff --git a/src/expand/main.rs.html b/src/expand/main.rs.html new file mode 100644 index 000000000..71c3a4639 --- /dev/null +++ b/src/expand/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_expand);
+
+
\ No newline at end of file diff --git a/src/expr/main.rs.html b/src/expr/main.rs.html new file mode 100644 index 000000000..7e08d8661 --- /dev/null +++ b/src/expr/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_expr);
+
+
\ No newline at end of file diff --git a/src/factor/main.rs.html b/src/factor/main.rs.html new file mode 100644 index 000000000..ab80317af --- /dev/null +++ b/src/factor/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_factor);
+
+
\ No newline at end of file diff --git a/src/false/main.rs.html b/src/false/main.rs.html new file mode 100644 index 000000000..221711f3a --- /dev/null +++ b/src/false/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_false);
+
+
\ No newline at end of file diff --git a/src/fmt/main.rs.html b/src/fmt/main.rs.html new file mode 100644 index 000000000..2bcc12707 --- /dev/null +++ b/src/fmt/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_fmt);
+
+
\ No newline at end of file diff --git a/src/fold/main.rs.html b/src/fold/main.rs.html new file mode 100644 index 000000000..d18124360 --- /dev/null +++ b/src/fold/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_fold);
+
+
\ No newline at end of file diff --git a/src/groups/main.rs.html b/src/groups/main.rs.html new file mode 100644 index 000000000..26f4a5fc7 --- /dev/null +++ b/src/groups/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_groups);
+
+
\ No newline at end of file diff --git a/src/hashsum/main.rs.html b/src/hashsum/main.rs.html new file mode 100644 index 000000000..c4a0bb9bc --- /dev/null +++ b/src/hashsum/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_hashsum);
+
+
\ No newline at end of file diff --git a/src/head/main.rs.html b/src/head/main.rs.html new file mode 100644 index 000000000..845ba554a --- /dev/null +++ b/src/head/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_head);
+
+
\ No newline at end of file diff --git a/src/hostid/main.rs.html b/src/hostid/main.rs.html new file mode 100644 index 000000000..a573b16bd --- /dev/null +++ b/src/hostid/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_hostid);
+
+
\ No newline at end of file diff --git a/src/hostname/main.rs.html b/src/hostname/main.rs.html new file mode 100644 index 000000000..58e4f5567 --- /dev/null +++ b/src/hostname/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_hostname);
+
+
\ No newline at end of file diff --git a/src/id/main.rs.html b/src/id/main.rs.html new file mode 100644 index 000000000..8e547af02 --- /dev/null +++ b/src/id/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_id);
+
+
\ No newline at end of file diff --git a/src/install/main.rs.html b/src/install/main.rs.html new file mode 100644 index 000000000..f39ff5a38 --- /dev/null +++ b/src/install/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_install);
+
+
\ No newline at end of file diff --git a/src/join/main.rs.html b/src/join/main.rs.html new file mode 100644 index 000000000..2e25ac27f --- /dev/null +++ b/src/join/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_join);
+
+
\ No newline at end of file diff --git a/src/kill/main.rs.html b/src/kill/main.rs.html new file mode 100644 index 000000000..3149e635b --- /dev/null +++ b/src/kill/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_kill);
+
+
\ No newline at end of file diff --git a/src/libstdbuf/libstdbuf.rs.html b/src/libstdbuf/libstdbuf.rs.html new file mode 100644 index 000000000..150718eb9 --- /dev/null +++ b/src/libstdbuf/libstdbuf.rs.html @@ -0,0 +1,149 @@ +libstdbuf.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+
+// spell-checker:ignore (ToDO) IOFBF IOLBF IONBF cstdio setvbuf
+
+#[macro_use]
+extern crate cpp;
+
+#[macro_use]
+extern crate uucore;
+
+use libc::{c_char, c_int, size_t, FILE, _IOFBF, _IOLBF, _IONBF};
+use std::env;
+use std::ptr;
+
+cpp! {{
+    #include <cstdio>
+
+    extern "C" {
+        void __stdbuf(void);
+
+        void __attribute((constructor))
+        __stdbuf_init(void) {
+            __stdbuf();
+        }
+
+        FILE *__stdbuf_get_stdin() { return stdin; }
+        FILE *__stdbuf_get_stdout() { return stdout; }
+        FILE *__stdbuf_get_stderr() { return stderr; }
+    }
+}}
+
+extern "C" {
+    fn __stdbuf_get_stdin() -> *mut FILE;
+    fn __stdbuf_get_stdout() -> *mut FILE;
+    fn __stdbuf_get_stderr() -> *mut FILE;
+}
+
+fn set_buffer(stream: *mut FILE, value: &str) {
+    let (mode, size): (c_int, size_t) = match value {
+        "0" => (_IONBF, 0_usize),
+        "L" => (_IOLBF, 0_usize),
+        input => {
+            let buff_size: usize = match input.parse() {
+                Ok(num) => num,
+                Err(e) => crash!(1, "incorrect size of buffer!: {}", e),
+            };
+            (_IOFBF, buff_size as size_t)
+        }
+    };
+    let res: c_int;
+    unsafe {
+        let buffer: *mut c_char = ptr::null_mut();
+        assert!(buffer.is_null());
+        res = libc::setvbuf(stream, buffer, mode, size);
+    }
+    if res != 0 {
+        crash!(res, "error while calling setvbuf!");
+    }
+}
+
+/// # Safety
+/// ToDO ... (safety note)
+#[no_mangle]
+pub unsafe extern "C" fn __stdbuf() {
+    if let Ok(val) = env::var("_STDBUF_E") {
+        set_buffer(__stdbuf_get_stderr(), &val);
+    }
+    if let Ok(val) = env::var("_STDBUF_I") {
+        set_buffer(__stdbuf_get_stdin(), &val);
+    }
+    if let Ok(val) = env::var("_STDBUF_O") {
+        set_buffer(__stdbuf_get_stdout(), &val);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/link/main.rs.html b/src/link/main.rs.html new file mode 100644 index 000000000..2ea2dff4c --- /dev/null +++ b/src/link/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_link);
+
+
\ No newline at end of file diff --git a/src/ln/main.rs.html b/src/ln/main.rs.html new file mode 100644 index 000000000..71449fa2f --- /dev/null +++ b/src/ln/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_ln);
+
+
\ No newline at end of file diff --git a/src/logname/main.rs.html b/src/logname/main.rs.html new file mode 100644 index 000000000..f67954fc6 --- /dev/null +++ b/src/logname/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_logname);
+
+
\ No newline at end of file diff --git a/src/ls/main.rs.html b/src/ls/main.rs.html new file mode 100644 index 000000000..8887f6aa2 --- /dev/null +++ b/src/ls/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_ls);
+
+
\ No newline at end of file diff --git a/src/mkdir/main.rs.html b/src/mkdir/main.rs.html new file mode 100644 index 000000000..f73871db0 --- /dev/null +++ b/src/mkdir/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_mkdir);
+
+
\ No newline at end of file diff --git a/src/mkfifo/main.rs.html b/src/mkfifo/main.rs.html new file mode 100644 index 000000000..e791f0e64 --- /dev/null +++ b/src/mkfifo/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_mkfifo);
+
+
\ No newline at end of file diff --git a/src/mknod/main.rs.html b/src/mknod/main.rs.html new file mode 100644 index 000000000..9c4b4663d --- /dev/null +++ b/src/mknod/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_mknod);
+
+
\ No newline at end of file diff --git a/src/mktemp/main.rs.html b/src/mktemp/main.rs.html new file mode 100644 index 000000000..f73ecb413 --- /dev/null +++ b/src/mktemp/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_mktemp);
+
+
\ No newline at end of file diff --git a/src/more/main.rs.html b/src/more/main.rs.html new file mode 100644 index 000000000..d32ac7b2e --- /dev/null +++ b/src/more/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_more);
+
+
\ No newline at end of file diff --git a/src/mv/main.rs.html b/src/mv/main.rs.html new file mode 100644 index 000000000..bda09cd01 --- /dev/null +++ b/src/mv/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_mv);
+
+
\ No newline at end of file diff --git a/src/nice/main.rs.html b/src/nice/main.rs.html new file mode 100644 index 000000000..4ecd2a48c --- /dev/null +++ b/src/nice/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_nice);
+
+
\ No newline at end of file diff --git a/src/nl/main.rs.html b/src/nl/main.rs.html new file mode 100644 index 000000000..3b0bc8d22 --- /dev/null +++ b/src/nl/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_nl);
+
+
\ No newline at end of file diff --git a/src/nohup/main.rs.html b/src/nohup/main.rs.html new file mode 100644 index 000000000..352c55754 --- /dev/null +++ b/src/nohup/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_nohup);
+
+
\ No newline at end of file diff --git a/src/nproc/main.rs.html b/src/nproc/main.rs.html new file mode 100644 index 000000000..d4dfc79d6 --- /dev/null +++ b/src/nproc/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_nproc);
+
+
\ No newline at end of file diff --git a/src/numfmt/main.rs.html b/src/numfmt/main.rs.html new file mode 100644 index 000000000..b7a94422e --- /dev/null +++ b/src/numfmt/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_numfmt);
+
+
\ No newline at end of file diff --git a/src/od/main.rs.html b/src/od/main.rs.html new file mode 100644 index 000000000..40293fea1 --- /dev/null +++ b/src/od/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_od);
+
+
\ No newline at end of file diff --git a/src/paste/main.rs.html b/src/paste/main.rs.html new file mode 100644 index 000000000..522abeac5 --- /dev/null +++ b/src/paste/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_paste);
+
+
\ No newline at end of file diff --git a/src/pathchk/main.rs.html b/src/pathchk/main.rs.html new file mode 100644 index 000000000..3df0a871c --- /dev/null +++ b/src/pathchk/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_pathchk);
+
+
\ No newline at end of file diff --git a/src/pinky/main.rs.html b/src/pinky/main.rs.html new file mode 100644 index 000000000..37dd1c30e --- /dev/null +++ b/src/pinky/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_pinky);
+
+
\ No newline at end of file diff --git a/src/pr/main.rs.html b/src/pr/main.rs.html new file mode 100644 index 000000000..51a4bef9c --- /dev/null +++ b/src/pr/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_pr); // spell-checker:ignore procs uucore
+
+
\ No newline at end of file diff --git a/src/printenv/main.rs.html b/src/printenv/main.rs.html new file mode 100644 index 000000000..badf1bc05 --- /dev/null +++ b/src/printenv/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_printenv);
+
+
\ No newline at end of file diff --git a/src/printf/main.rs.html b/src/printf/main.rs.html new file mode 100644 index 000000000..64711039f --- /dev/null +++ b/src/printf/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_printf);
+
+
\ No newline at end of file diff --git a/src/ptx/main.rs.html b/src/ptx/main.rs.html new file mode 100644 index 000000000..0afb3a581 --- /dev/null +++ b/src/ptx/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_ptx);
+
+
\ No newline at end of file diff --git a/src/pwd/main.rs.html b/src/pwd/main.rs.html new file mode 100644 index 000000000..c796c33b1 --- /dev/null +++ b/src/pwd/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_pwd);
+
+
\ No newline at end of file diff --git a/src/readlink/main.rs.html b/src/readlink/main.rs.html new file mode 100644 index 000000000..20b73c522 --- /dev/null +++ b/src/readlink/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_readlink);
+
+
\ No newline at end of file diff --git a/src/realpath/main.rs.html b/src/realpath/main.rs.html new file mode 100644 index 000000000..a11c36f36 --- /dev/null +++ b/src/realpath/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_realpath);
+
+
\ No newline at end of file diff --git a/src/relpath/main.rs.html b/src/relpath/main.rs.html new file mode 100644 index 000000000..ae3991435 --- /dev/null +++ b/src/relpath/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_relpath);
+
+
\ No newline at end of file diff --git a/src/rm/main.rs.html b/src/rm/main.rs.html new file mode 100644 index 000000000..445f5c743 --- /dev/null +++ b/src/rm/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_rm);
+
+
\ No newline at end of file diff --git a/src/rmdir/main.rs.html b/src/rmdir/main.rs.html new file mode 100644 index 000000000..5b2563430 --- /dev/null +++ b/src/rmdir/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_rmdir);
+
+
\ No newline at end of file diff --git a/src/runcon/main.rs.html b/src/runcon/main.rs.html new file mode 100644 index 000000000..b37ed3b25 --- /dev/null +++ b/src/runcon/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_runcon);
+
+
\ No newline at end of file diff --git a/src/seq/main.rs.html b/src/seq/main.rs.html new file mode 100644 index 000000000..23ad6d23e --- /dev/null +++ b/src/seq/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_seq);
+
+
\ No newline at end of file diff --git a/src/shred/main.rs.html b/src/shred/main.rs.html new file mode 100644 index 000000000..cabbc0737 --- /dev/null +++ b/src/shred/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_shred);
+
+
\ No newline at end of file diff --git a/src/shuf/main.rs.html b/src/shuf/main.rs.html new file mode 100644 index 000000000..3b723d932 --- /dev/null +++ b/src/shuf/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_shuf);
+
+
\ No newline at end of file diff --git a/src/sleep/main.rs.html b/src/sleep/main.rs.html new file mode 100644 index 000000000..447866af6 --- /dev/null +++ b/src/sleep/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_sleep);
+
+
\ No newline at end of file diff --git a/src/sort/main.rs.html b/src/sort/main.rs.html new file mode 100644 index 000000000..2634c9654 --- /dev/null +++ b/src/sort/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_sort);
+
+
\ No newline at end of file diff --git a/src/split/main.rs.html b/src/split/main.rs.html new file mode 100644 index 000000000..6e7aea3dd --- /dev/null +++ b/src/split/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_split);
+
+
\ No newline at end of file diff --git a/src/stat/main.rs.html b/src/stat/main.rs.html new file mode 100644 index 000000000..bb4507720 --- /dev/null +++ b/src/stat/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_stat);
+
+
\ No newline at end of file diff --git a/src/stdbuf/main.rs.html b/src/stdbuf/main.rs.html new file mode 100644 index 000000000..26191e512 --- /dev/null +++ b/src/stdbuf/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_stdbuf);
+
+
\ No newline at end of file diff --git a/src/sum/main.rs.html b/src/sum/main.rs.html new file mode 100644 index 000000000..78e16d42a --- /dev/null +++ b/src/sum/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_sum);
+
+
\ No newline at end of file diff --git a/src/sync/main.rs.html b/src/sync/main.rs.html new file mode 100644 index 000000000..1745a3f47 --- /dev/null +++ b/src/sync/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_sync);
+
+
\ No newline at end of file diff --git a/src/tac/main.rs.html b/src/tac/main.rs.html new file mode 100644 index 000000000..a30d0bd33 --- /dev/null +++ b/src/tac/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_tac);
+
+
\ No newline at end of file diff --git a/src/tail/main.rs.html b/src/tail/main.rs.html new file mode 100644 index 000000000..b2dab292b --- /dev/null +++ b/src/tail/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_tail);
+
+
\ No newline at end of file diff --git a/src/tee/main.rs.html b/src/tee/main.rs.html new file mode 100644 index 000000000..716607308 --- /dev/null +++ b/src/tee/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_tee);
+
+
\ No newline at end of file diff --git a/src/test/main.rs.html b/src/test/main.rs.html new file mode 100644 index 000000000..ffe32d84c --- /dev/null +++ b/src/test/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_test);
+
+
\ No newline at end of file diff --git a/src/timeout/main.rs.html b/src/timeout/main.rs.html new file mode 100644 index 000000000..51e48248d --- /dev/null +++ b/src/timeout/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_timeout);
+
+
\ No newline at end of file diff --git a/src/touch/main.rs.html b/src/touch/main.rs.html new file mode 100644 index 000000000..a50bae47c --- /dev/null +++ b/src/touch/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_touch);
+
+
\ No newline at end of file diff --git a/src/tr/main.rs.html b/src/tr/main.rs.html new file mode 100644 index 000000000..a8923e2d6 --- /dev/null +++ b/src/tr/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_tr);
+
+
\ No newline at end of file diff --git a/src/true/main.rs.html b/src/true/main.rs.html new file mode 100644 index 000000000..475873e92 --- /dev/null +++ b/src/true/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_true);
+
+
\ No newline at end of file diff --git a/src/truncate/main.rs.html b/src/truncate/main.rs.html new file mode 100644 index 000000000..e1147733b --- /dev/null +++ b/src/truncate/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_truncate);
+
+
\ No newline at end of file diff --git a/src/tsort/main.rs.html b/src/tsort/main.rs.html new file mode 100644 index 000000000..f68689d15 --- /dev/null +++ b/src/tsort/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_tsort);
+
+
\ No newline at end of file diff --git a/src/tty/main.rs.html b/src/tty/main.rs.html new file mode 100644 index 000000000..15f87f305 --- /dev/null +++ b/src/tty/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_tty);
+
+
\ No newline at end of file diff --git a/src/uname/main.rs.html b/src/uname/main.rs.html new file mode 100644 index 000000000..7e761b78b --- /dev/null +++ b/src/uname/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_uname);
+
+
\ No newline at end of file diff --git a/src/unexpand/main.rs.html b/src/unexpand/main.rs.html new file mode 100644 index 000000000..fd1b96c23 --- /dev/null +++ b/src/unexpand/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_unexpand);
+
+
\ No newline at end of file diff --git a/src/uniq/main.rs.html b/src/uniq/main.rs.html new file mode 100644 index 000000000..ee1545415 --- /dev/null +++ b/src/uniq/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_uniq);
+
+
\ No newline at end of file diff --git a/src/unlink/main.rs.html b/src/unlink/main.rs.html new file mode 100644 index 000000000..84231b2f1 --- /dev/null +++ b/src/unlink/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_unlink);
+
+
\ No newline at end of file diff --git a/src/uptime/main.rs.html b/src/uptime/main.rs.html new file mode 100644 index 000000000..4e5ac9a63 --- /dev/null +++ b/src/uptime/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_uptime);
+
+
\ No newline at end of file diff --git a/src/users/main.rs.html b/src/users/main.rs.html new file mode 100644 index 000000000..e7b9ed33e --- /dev/null +++ b/src/users/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_users);
+
+
\ No newline at end of file diff --git a/src/uu_arch/arch.rs.html b/src/uu_arch/arch.rs.html new file mode 100644 index 000000000..de92ba159 --- /dev/null +++ b/src/uu_arch/arch.rs.html @@ -0,0 +1,73 @@ +arch.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Smigle00 <smigle00@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use platform_info::*;
+
+use clap::{crate_version, App};
+use uucore::error::{FromIo, UResult};
+
+static ABOUT: &str = "Display machine architecture";
+static SUMMARY: &str = "Determine architecture name for current machine.";
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    uu_app().get_matches_from(args);
+
+    let uts = PlatformInfo::new().map_err_context(|| "cannot get system name".to_string())?;
+    println!("{}", uts.machine().trim());
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(SUMMARY)
+}
+
+
\ No newline at end of file diff --git a/src/uu_base32/base32.rs.html b/src/uu_base32/base32.rs.html new file mode 100644 index 000000000..49c7d64f6 --- /dev/null +++ b/src/uu_base32/base32.rs.html @@ -0,0 +1,131 @@ +base32.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use std::io::{stdin, Read};
+
+use clap::App;
+use uucore::encoding::Format;
+
+pub mod base_common;
+
+static ABOUT: &str = "
+ With no FILE, or when FILE is -, read standard input.
+
+ The data are encoded as described for the base32 alphabet in RFC
+ 4648. When decoding, the input may contain newlines in addition
+ to the bytes of the formal base32 alphabet. Use --ignore-garbage
+ to attempt to recover from any other non-alphabet bytes in the
+ encoded stream.
+";
+static VERSION: &str = env!("CARGO_PKG_VERSION");
+
+static BASE_CMD_PARSE_ERROR: i32 = 1;
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let format = Format::Base32;
+    let usage = usage();
+    let name = uucore::util_name();
+
+    let config_result: Result<base_common::Config, String> =
+        base_common::parse_base_cmd_args(args, &name, VERSION, ABOUT, &usage);
+    let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));
+
+    // Create a reference to stdin so we can return a locked stdin from
+    // parse_base_cmd_args
+    let stdin_raw = stdin();
+    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw);
+
+    base_common::handle_input(
+        &mut input,
+        format,
+        config.wrap_cols,
+        config.ignore_garbage,
+        config.decode,
+        &name,
+    );
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    base_common::base_app(&uucore::util_name(), VERSION, ABOUT)
+}
+
+
\ No newline at end of file diff --git a/src/uu_base32/base_common.rs.html b/src/uu_base32/base_common.rs.html new file mode 100644 index 000000000..752298d92 --- /dev/null +++ b/src/uu_base32/base_common.rs.html @@ -0,0 +1,355 @@ +base_common.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+// (c) Alex Lyon <arcterus@mail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+use std::io::{stdout, Read, Write};
+
+use uucore::encoding::{wrap_print, Data, Format};
+use uucore::InvalidEncodingHandling;
+
+use std::fs::File;
+use std::io::{BufReader, Stdin};
+use std::path::Path;
+
+use clap::{App, Arg};
+
+// Config.
+pub struct Config {
+    pub decode: bool,
+    pub ignore_garbage: bool,
+    pub wrap_cols: Option<usize>,
+    pub to_read: Option<String>,
+}
+
+pub mod options {
+    pub static DECODE: &str = "decode";
+    pub static WRAP: &str = "wrap";
+    pub static IGNORE_GARBAGE: &str = "ignore-garbage";
+    pub static FILE: &str = "file";
+}
+
+impl Config {
+    pub fn from(app_name: &str, options: &clap::ArgMatches) -> Result<Config, String> {
+        let file: Option<String> = match options.values_of(options::FILE) {
+            Some(mut values) => {
+                let name = values.next().unwrap();
+                if let Some(extra_op) = values.next() {
+                    return Err(format!(
+                        "extra operand '{}'\nTry '{} --help' for more information.",
+                        extra_op, app_name
+                    ));
+                }
+
+                if name == "-" {
+                    None
+                } else {
+                    if !Path::exists(Path::new(name)) {
+                        return Err(format!("{}: No such file or directory", name));
+                    }
+                    Some(name.to_owned())
+                }
+            }
+            None => None,
+        };
+
+        let cols = options
+            .value_of(options::WRAP)
+            .map(|num| {
+                num.parse::<usize>()
+                    .map_err(|_| format!("invalid wrap size: '{}'", num))
+            })
+            .transpose()?;
+
+        Ok(Config {
+            decode: options.is_present(options::DECODE),
+            ignore_garbage: options.is_present(options::IGNORE_GARBAGE),
+            wrap_cols: cols,
+            to_read: file,
+        })
+    }
+}
+
+pub fn parse_base_cmd_args(
+    args: impl uucore::Args,
+    name: &str,
+    version: &str,
+    about: &str,
+    usage: &str,
+) -> Result<Config, String> {
+    let app = base_app(name, version, about).usage(usage);
+    let arg_list = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+    Config::from(name, &app.get_matches_from(arg_list))
+}
+
+pub fn base_app<'a>(name: &str, version: &'a str, about: &'a str) -> App<'static, 'a> {
+    App::new(name)
+        .version(version)
+        .about(about)
+        // Format arguments.
+        .arg(
+            Arg::with_name(options::DECODE)
+                .short("d")
+                .long(options::DECODE)
+                .help("decode data"),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_GARBAGE)
+                .short("i")
+                .long(options::IGNORE_GARBAGE)
+                .help("when decoding, ignore non-alphabetic characters"),
+        )
+        .arg(
+            Arg::with_name(options::WRAP)
+                .short("w")
+                .long(options::WRAP)
+                .takes_value(true)
+                .help(
+                    "wrap encoded lines after COLS character (default 76, 0 to disable wrapping)",
+                ),
+        )
+        // "multiple" arguments are used to check whether there is more than one
+        // file passed in.
+        .arg(Arg::with_name(options::FILE).index(1).multiple(true))
+}
+
+pub fn get_input<'a>(config: &Config, stdin_ref: &'a Stdin) -> Box<dyn Read + 'a> {
+    match &config.to_read {
+        Some(name) => {
+            let file_buf = safe_unwrap!(File::open(Path::new(name)));
+            Box::new(BufReader::new(file_buf)) // as Box<dyn Read>
+        }
+        None => {
+            Box::new(stdin_ref.lock()) // as Box<dyn Read>
+        }
+    }
+}
+
+pub fn handle_input<R: Read>(
+    input: &mut R,
+    format: Format,
+    line_wrap: Option<usize>,
+    ignore_garbage: bool,
+    decode: bool,
+    name: &str,
+) {
+    let mut data = Data::new(input, format).ignore_garbage(ignore_garbage);
+    if let Some(wrap) = line_wrap {
+        data = data.line_wrap(wrap);
+    }
+
+    if !decode {
+        match data.encode() {
+            Ok(s) => {
+                wrap_print(&data, s);
+            }
+            Err(_) => {
+                eprintln!(
+                    "{}: error: invalid input (length must be multiple of 4 characters)",
+                    name
+                );
+                exit!(1)
+            }
+        }
+    } else {
+        match data.decode() {
+            Ok(s) => {
+                if stdout().write_all(&s).is_err() {
+                    // on windows console, writing invalid utf8 returns an error
+                    eprintln!("{}: error: Cannot write non-utf8 data", name);
+                    exit!(1)
+                }
+            }
+            Err(_) => {
+                eprintln!("{}: error: invalid input", name);
+                exit!(1)
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_base64/base64.rs.html b/src/uu_base64/base64.rs.html new file mode 100644 index 000000000..d638333dd --- /dev/null +++ b/src/uu_base64/base64.rs.html @@ -0,0 +1,123 @@ +base64.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use uu_base32::base_common;
+pub use uu_base32::uu_app;
+
+use uucore::encoding::Format;
+
+use std::io::{stdin, Read};
+
+static ABOUT: &str = "
+ With no FILE, or when FILE is -, read standard input.
+
+ The data are encoded as described for the base64 alphabet in RFC
+ 3548. When decoding, the input may contain newlines in addition
+ to the bytes of the formal base64 alphabet. Use --ignore-garbage
+ to attempt to recover from any other non-alphabet bytes in the
+ encoded stream.
+";
+static VERSION: &str = env!("CARGO_PKG_VERSION");
+
+static BASE_CMD_PARSE_ERROR: i32 = 1;
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let format = Format::Base64;
+    let usage = usage();
+    let name = uucore::util_name();
+    let config_result: Result<base_common::Config, String> =
+        base_common::parse_base_cmd_args(args, &name, VERSION, ABOUT, &usage);
+    let config = config_result.unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s));
+
+    // Create a reference to stdin so we can return a locked stdin from
+    // parse_base_cmd_args
+    let stdin_raw = stdin();
+    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw);
+
+    base_common::handle_input(
+        &mut input,
+        format,
+        config.wrap_cols,
+        config.ignore_garbage,
+        config.decode,
+        &name,
+    );
+
+    0
+}
+
+
\ No newline at end of file diff --git a/src/uu_basename/basename.rs.html b/src/uu_basename/basename.rs.html new file mode 100644 index 000000000..e4aa040f9 --- /dev/null +++ b/src/uu_basename/basename.rs.html @@ -0,0 +1,307 @@ +basename.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jimmy Lu <jimmy.lu.2011@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) fullname
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::path::{is_separator, PathBuf};
+use uucore::InvalidEncodingHandling;
+
+static SUMMARY: &str = "Print NAME with any leading directory components removed
+If specified, also remove a trailing SUFFIX";
+
+fn usage() -> String {
+    format!(
+        "{0} NAME [SUFFIX]
+    {0} OPTION... NAME...",
+        uucore::execution_phrase()
+    )
+}
+
+pub mod options {
+    pub static MULTIPLE: &str = "multiple";
+    pub static NAME: &str = "name";
+    pub static SUFFIX: &str = "suffix";
+    pub static ZERO: &str = "zero";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+    let usage = usage();
+    //
+    // Argument parsing
+    //
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    // too few arguments
+    if !matches.is_present(options::NAME) {
+        crash!(
+            1,
+            "{1}\nTry '{0} --help' for more information.",
+            uucore::execution_phrase(),
+            "missing operand"
+        );
+    }
+
+    let opt_suffix = matches.is_present(options::SUFFIX);
+    let opt_multiple = matches.is_present(options::MULTIPLE);
+    let opt_zero = matches.is_present(options::ZERO);
+    let multiple_paths = opt_suffix || opt_multiple;
+    // too many arguments
+    if !multiple_paths && matches.occurrences_of(options::NAME) > 2 {
+        crash!(
+            1,
+            "extra operand '{1}'\nTry '{0} --help' for more information.",
+            uucore::execution_phrase(),
+            matches.values_of(options::NAME).unwrap().nth(2).unwrap()
+        );
+    }
+
+    let suffix = if opt_suffix {
+        matches.value_of(options::SUFFIX).unwrap()
+    } else if !opt_multiple && matches.occurrences_of(options::NAME) > 1 {
+        matches.values_of(options::NAME).unwrap().nth(1).unwrap()
+    } else {
+        ""
+    };
+
+    //
+    // Main Program Processing
+    //
+
+    let paths: Vec<_> = if multiple_paths {
+        matches.values_of(options::NAME).unwrap().collect()
+    } else {
+        matches.values_of(options::NAME).unwrap().take(1).collect()
+    };
+
+    let line_ending = if opt_zero { "\0" } else { "\n" };
+    for path in paths {
+        print!("{}{}", basename(path, suffix), line_ending);
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(SUMMARY)
+        .arg(
+            Arg::with_name(options::MULTIPLE)
+                .short("a")
+                .long(options::MULTIPLE)
+                .help("support multiple arguments and treat each as a NAME"),
+        )
+        .arg(Arg::with_name(options::NAME).multiple(true).hidden(true))
+        .arg(
+            Arg::with_name(options::SUFFIX)
+                .short("s")
+                .long(options::SUFFIX)
+                .value_name("SUFFIX")
+                .help("remove a trailing SUFFIX; implies -a"),
+        )
+        .arg(
+            Arg::with_name(options::ZERO)
+                .short("z")
+                .long(options::ZERO)
+                .help("end each output line with NUL, not newline"),
+        )
+}
+
+fn basename(fullname: &str, suffix: &str) -> String {
+    // Remove all platform-specific path separators from the end.
+    let path = fullname.trim_end_matches(is_separator);
+
+    // If the path contained *only* suffix characters (for example, if
+    // `fullname` were "///" and `suffix` were "/"), then `path` would
+    // be left with the empty string. In that case, we set `path` to be
+    // the original `fullname` to avoid returning the empty path.
+    let path = if path.is_empty() { fullname } else { path };
+
+    // Convert to path buffer and get last path component
+    let pb = PathBuf::from(path);
+    match pb.components().last() {
+        Some(c) => strip_suffix(c.as_os_str().to_str().unwrap(), suffix),
+        None => "".to_owned(),
+    }
+}
+
+// can be replaced with strip_suffix once MSRV is 1.45
+#[allow(clippy::manual_strip)]
+fn strip_suffix(name: &str, suffix: &str) -> String {
+    if name == suffix {
+        return name.to_owned();
+    }
+
+    if name.ends_with(suffix) {
+        return name[..name.len() - suffix.len()].to_owned();
+    }
+
+    name.to_owned()
+}
+
+
\ No newline at end of file diff --git a/src/uu_basenc/basenc.rs.html b/src/uu_basenc/basenc.rs.html new file mode 100644 index 000000000..3d331e4b5 --- /dev/null +++ b/src/uu_basenc/basenc.rs.html @@ -0,0 +1,195 @@ +basenc.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+//spell-checker:ignore (args) lsbf msbf
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use uu_base32::base_common::{self, Config};
+
+use uucore::{encoding::Format, InvalidEncodingHandling};
+
+use std::io::{stdin, Read};
+
+static ABOUT: &str = "
+ With no FILE, or when FILE is -, read standard input.
+
+ When decoding, the input may contain newlines in addition to the bytes of
+ the formal alphabet. Use --ignore-garbage to attempt to recover
+ from any other non-alphabet bytes in the encoded stream.
+";
+
+static BASE_CMD_PARSE_ERROR: i32 = 1;
+
+const ENCODINGS: &[(&str, Format)] = &[
+    ("base64", Format::Base64),
+    ("base64url", Format::Base64Url),
+    ("base32", Format::Base32),
+    ("base32hex", Format::Base32Hex),
+    ("base16", Format::Base16),
+    ("base2lsbf", Format::Base2Lsbf),
+    ("base2msbf", Format::Base2Msbf),
+    ("z85", Format::Z85),
+    // common abbreviations. TODO: once we have clap 3.0 we can use `AppSettings::InferLongArgs` to get all abbreviations automatically
+    ("base2l", Format::Base2Lsbf),
+    ("base2m", Format::Base2Msbf),
+];
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    let mut app = base_common::base_app(&uucore::util_name(), crate_version!(), ABOUT);
+    for encoding in ENCODINGS {
+        app = app.arg(Arg::with_name(encoding.0).long(encoding.0));
+    }
+    app
+}
+
+fn parse_cmd_args(args: impl uucore::Args) -> (Config, Format) {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(
+        args.collect_str(InvalidEncodingHandling::ConvertLossy)
+            .accept_any(),
+    );
+    let format = ENCODINGS
+        .iter()
+        .find(|encoding| matches.is_present(encoding.0))
+        .unwrap_or_else(|| {
+            show_usage_error!("missing encoding type");
+            std::process::exit(1)
+        })
+        .1;
+    (
+        Config::from("basenc", &matches).unwrap_or_else(|s| crash!(BASE_CMD_PARSE_ERROR, "{}", s)),
+        format,
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let name = uucore::util_name();
+    let (config, format) = parse_cmd_args(args);
+    // Create a reference to stdin so we can return a locked stdin from
+    // parse_base_cmd_args
+    let stdin_raw = stdin();
+    let mut input: Box<dyn Read> = base_common::get_input(&config, &stdin_raw);
+
+    base_common::handle_input(
+        &mut input,
+        format,
+        config.wrap_cols,
+        config.ignore_garbage,
+        config.decode,
+        &name,
+    );
+
+    0
+}
+
+
\ No newline at end of file diff --git a/src/uu_cat/cat.rs.html b/src/uu_cat/cat.rs.html new file mode 100644 index 000000000..779b0b8f2 --- /dev/null +++ b/src/uu_cat/cat.rs.html @@ -0,0 +1,1313 @@ +cat.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jordi Boggiano <j.boggiano@seld.be>
+// (c) Evgeniy Klyuchikov <evgeniy.klyuchikov@gmail.com>
+// (c) Joshua S. Miller <jsmiller@uchicago.edu>
+// (c) Árni Dagur <arni@dagur.eu>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) nonprint nonblank nonprinting
+
+#[cfg(unix)]
+extern crate unix_socket;
+#[macro_use]
+extern crate uucore;
+
+// last synced with: cat (GNU coreutils) 8.13
+use clap::{crate_version, App, Arg};
+use std::fs::{metadata, File};
+use std::io::{self, Read, Write};
+use thiserror::Error;
+use uucore::error::UResult;
+
+#[cfg(unix)]
+use std::os::unix::io::AsRawFd;
+
+/// Linux splice support
+#[cfg(any(target_os = "linux", target_os = "android"))]
+mod splice;
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use std::os::unix::io::RawFd;
+
+/// Unix domain socket support
+#[cfg(unix)]
+use std::net::Shutdown;
+#[cfg(unix)]
+use std::os::unix::fs::FileTypeExt;
+#[cfg(unix)]
+use unix_socket::UnixStream;
+use uucore::InvalidEncodingHandling;
+
+static NAME: &str = "cat";
+static SYNTAX: &str = "[OPTION]... [FILE]...";
+static SUMMARY: &str = "Concatenate FILE(s), or standard input, to standard output
+ With no FILE, or when FILE is -, read standard input.";
+
+#[derive(Error, Debug)]
+enum CatError {
+    /// Wrapper around `io::Error`
+    #[error("{0}")]
+    Io(#[from] io::Error),
+    /// Wrapper around `nix::Error`
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    #[error("{0}")]
+    Nix(#[from] nix::Error),
+    /// Unknown file type; it's not a regular file, socket, etc.
+    #[error("unknown filetype: {}", ft_debug)]
+    UnknownFiletype {
+        /// A debug print of the file type
+        ft_debug: String,
+    },
+    #[error("Is a directory")]
+    IsDirectory,
+    #[error("input file is output file")]
+    OutputIsInput,
+}
+
+type CatResult<T> = Result<T, CatError>;
+
+#[derive(PartialEq)]
+enum NumberingMode {
+    None,
+    NonEmpty,
+    All,
+}
+
+struct OutputOptions {
+    /// Line numbering mode
+    number: NumberingMode,
+
+    /// Suppress repeated empty output lines
+    squeeze_blank: bool,
+
+    /// display TAB characters as `tab`
+    show_tabs: bool,
+
+    /// Show end of lines
+    show_ends: bool,
+
+    /// use ^ and M- notation, except for LF (\\n) and TAB (\\t)
+    show_nonprint: bool,
+}
+
+impl OutputOptions {
+    fn tab(&self) -> &'static str {
+        if self.show_tabs {
+            "^I"
+        } else {
+            "\t"
+        }
+    }
+
+    fn end_of_line(&self) -> &'static str {
+        if self.show_ends {
+            "$\n"
+        } else {
+            "\n"
+        }
+    }
+
+    /// We can write fast if we can simply copy the contents of the file to
+    /// stdout, without augmenting the output with e.g. line numbers.
+    fn can_write_fast(&self) -> bool {
+        !(self.show_tabs
+            || self.show_nonprint
+            || self.show_ends
+            || self.squeeze_blank
+            || self.number != NumberingMode::None)
+    }
+}
+
+/// State that persists between output of each file. This struct is only used
+/// when we can't write fast.
+struct OutputState {
+    /// The current line number
+    line_number: usize,
+
+    /// Whether the output cursor is at the beginning of a new line
+    at_line_start: bool,
+
+    /// Whether we skipped a \r, which still needs to be printed
+    skipped_carriage_return: bool,
+
+    /// Whether we have already printed a blank line
+    one_blank_kept: bool,
+}
+
+/// Represents an open file handle, stream, or other device
+struct InputHandle<R: Read> {
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    file_descriptor: RawFd,
+    reader: R,
+    is_interactive: bool,
+}
+
+/// Concrete enum of recognized file types.
+///
+/// *Note*: `cat`-ing a directory should result in an
+/// CatError::IsDirectory
+enum InputType {
+    Directory,
+    File,
+    StdIn,
+    SymLink,
+    #[cfg(unix)]
+    BlockDevice,
+    #[cfg(unix)]
+    CharacterDevice,
+    #[cfg(unix)]
+    Fifo,
+    #[cfg(unix)]
+    Socket,
+}
+
+mod options {
+    pub static FILE: &str = "file";
+    pub static SHOW_ALL: &str = "show-all";
+    pub static NUMBER_NONBLANK: &str = "number-nonblank";
+    pub static SHOW_NONPRINTING_ENDS: &str = "e";
+    pub static SHOW_ENDS: &str = "show-ends";
+    pub static NUMBER: &str = "number";
+    pub static SQUEEZE_BLANK: &str = "squeeze-blank";
+    pub static SHOW_NONPRINTING_TABS: &str = "t";
+    pub static SHOW_TABS: &str = "show-tabs";
+    pub static SHOW_NONPRINTING: &str = "show-nonprinting";
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let number_mode = if matches.is_present(options::NUMBER_NONBLANK) {
+        NumberingMode::NonEmpty
+    } else if matches.is_present(options::NUMBER) {
+        NumberingMode::All
+    } else {
+        NumberingMode::None
+    };
+
+    let show_nonprint = vec![
+        options::SHOW_ALL.to_owned(),
+        options::SHOW_NONPRINTING_ENDS.to_owned(),
+        options::SHOW_NONPRINTING_TABS.to_owned(),
+        options::SHOW_NONPRINTING.to_owned(),
+    ]
+    .iter()
+    .any(|v| matches.is_present(v));
+
+    let show_ends = vec![
+        options::SHOW_ENDS.to_owned(),
+        options::SHOW_ALL.to_owned(),
+        options::SHOW_NONPRINTING_ENDS.to_owned(),
+    ]
+    .iter()
+    .any(|v| matches.is_present(v));
+
+    let show_tabs = vec![
+        options::SHOW_ALL.to_owned(),
+        options::SHOW_TABS.to_owned(),
+        options::SHOW_NONPRINTING_TABS.to_owned(),
+    ]
+    .iter()
+    .any(|v| matches.is_present(v));
+
+    let squeeze_blank = matches.is_present(options::SQUEEZE_BLANK);
+    let files: Vec<String> = match matches.values_of(options::FILE) {
+        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
+        None => vec!["-".to_owned()],
+    };
+
+    let options = OutputOptions {
+        show_ends,
+        number: number_mode,
+        show_nonprint,
+        show_tabs,
+        squeeze_blank,
+    };
+    cat_files(files, &options)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(SYNTAX)
+        .about(SUMMARY)
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+        .arg(
+            Arg::with_name(options::SHOW_ALL)
+                .short("A")
+                .long(options::SHOW_ALL)
+                .help("equivalent to -vET"),
+        )
+        .arg(
+            Arg::with_name(options::NUMBER_NONBLANK)
+                .short("b")
+                .long(options::NUMBER_NONBLANK)
+                .help("number nonempty output lines, overrides -n")
+                .overrides_with(options::NUMBER),
+        )
+        .arg(
+            Arg::with_name(options::SHOW_NONPRINTING_ENDS)
+                .short("e")
+                .help("equivalent to -vE"),
+        )
+        .arg(
+            Arg::with_name(options::SHOW_ENDS)
+                .short("E")
+                .long(options::SHOW_ENDS)
+                .help("display $ at end of each line"),
+        )
+        .arg(
+            Arg::with_name(options::NUMBER)
+                .short("n")
+                .long(options::NUMBER)
+                .help("number all output lines"),
+        )
+        .arg(
+            Arg::with_name(options::SQUEEZE_BLANK)
+                .short("s")
+                .long(options::SQUEEZE_BLANK)
+                .help("suppress repeated empty output lines"),
+        )
+        .arg(
+            Arg::with_name(options::SHOW_NONPRINTING_TABS)
+                .short("t")
+                .long(options::SHOW_NONPRINTING_TABS)
+                .help("equivalent to -vT"),
+        )
+        .arg(
+            Arg::with_name(options::SHOW_TABS)
+                .short("T")
+                .long(options::SHOW_TABS)
+                .help("display TAB characters at ^I"),
+        )
+        .arg(
+            Arg::with_name(options::SHOW_NONPRINTING)
+                .short("v")
+                .long(options::SHOW_NONPRINTING)
+                .help("use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
+        )
+}
+
+fn cat_handle<R: Read>(
+    handle: &mut InputHandle<R>,
+    options: &OutputOptions,
+    state: &mut OutputState,
+) -> CatResult<()> {
+    if options.can_write_fast() {
+        write_fast(handle)
+    } else {
+        write_lines(handle, options, state)
+    }
+}
+
+fn cat_path(
+    path: &str,
+    options: &OutputOptions,
+    state: &mut OutputState,
+    #[cfg(unix)] out_info: &nix::sys::stat::FileStat,
+    #[cfg(windows)] out_info: &winapi_util::file::Information,
+) -> CatResult<()> {
+    if path == "-" {
+        let stdin = io::stdin();
+        let mut handle = InputHandle {
+            #[cfg(any(target_os = "linux", target_os = "android"))]
+            file_descriptor: stdin.as_raw_fd(),
+            reader: stdin,
+            is_interactive: atty::is(atty::Stream::Stdin),
+        };
+        return cat_handle(&mut handle, options, state);
+    }
+    match get_input_type(path)? {
+        InputType::Directory => Err(CatError::IsDirectory),
+        #[cfg(unix)]
+        InputType::Socket => {
+            let socket = UnixStream::connect(path)?;
+            socket.shutdown(Shutdown::Write)?;
+            let mut handle = InputHandle {
+                #[cfg(any(target_os = "linux", target_os = "android"))]
+                file_descriptor: socket.as_raw_fd(),
+                reader: socket,
+                is_interactive: false,
+            };
+            cat_handle(&mut handle, options, state)
+        }
+        _ => {
+            let file = File::open(path)?;
+            #[cfg(any(windows, unix))]
+            if same_file(out_info, &file) {
+                return Err(CatError::OutputIsInput);
+            }
+            let mut handle = InputHandle {
+                #[cfg(any(target_os = "linux", target_os = "android"))]
+                file_descriptor: file.as_raw_fd(),
+                reader: file,
+                is_interactive: false,
+            };
+            cat_handle(&mut handle, options, state)
+        }
+    }
+}
+
+#[cfg(unix)]
+fn same_file(a_info: &nix::sys::stat::FileStat, b: &File) -> bool {
+    let b_info = nix::sys::stat::fstat(b.as_raw_fd()).unwrap();
+    b_info.st_size != 0 && b_info.st_dev == a_info.st_dev && b_info.st_ino == a_info.st_ino
+}
+
+#[cfg(windows)]
+fn same_file(a_info: &winapi_util::file::Information, b: &File) -> bool {
+    let b_info = winapi_util::file::information(b).unwrap();
+    b_info.file_size() != 0
+        && b_info.volume_serial_number() == a_info.volume_serial_number()
+        && b_info.file_index() == a_info.file_index()
+}
+
+fn cat_files(files: Vec<String>, options: &OutputOptions) -> UResult<()> {
+    #[cfg(windows)]
+    let out_info = winapi_util::file::information(&std::io::stdout()).unwrap();
+    #[cfg(unix)]
+    let out_info = nix::sys::stat::fstat(std::io::stdout().as_raw_fd()).unwrap();
+
+    let mut state = OutputState {
+        line_number: 1,
+        at_line_start: true,
+        skipped_carriage_return: false,
+        one_blank_kept: false,
+    };
+    let mut error_messages: Vec<String> = Vec::new();
+
+    for path in &files {
+        if let Err(err) = cat_path(path, options, &mut state, &out_info) {
+            error_messages.push(format!("{}: {}", path, err));
+        }
+    }
+    if state.skipped_carriage_return {
+        print!("\r");
+    }
+    if error_messages.is_empty() {
+        Ok(())
+    } else {
+        // each next line is expected to display "cat: …"
+        let line_joiner = format!("\n{}: ", uucore::util_name());
+
+        Err(uucore::error::USimpleError::new(
+            error_messages.len() as i32,
+            error_messages.join(&line_joiner),
+        ))
+    }
+}
+
+/// Classifies the `InputType` of file at `path` if possible
+///
+/// # Arguments
+///
+/// * `path` - Path on a file system to classify metadata
+fn get_input_type(path: &str) -> CatResult<InputType> {
+    if path == "-" {
+        return Ok(InputType::StdIn);
+    }
+
+    let ft = metadata(path)?.file_type();
+    match ft {
+        #[cfg(unix)]
+        ft if ft.is_block_device() => Ok(InputType::BlockDevice),
+        #[cfg(unix)]
+        ft if ft.is_char_device() => Ok(InputType::CharacterDevice),
+        #[cfg(unix)]
+        ft if ft.is_fifo() => Ok(InputType::Fifo),
+        #[cfg(unix)]
+        ft if ft.is_socket() => Ok(InputType::Socket),
+        ft if ft.is_dir() => Ok(InputType::Directory),
+        ft if ft.is_file() => Ok(InputType::File),
+        ft if ft.is_symlink() => Ok(InputType::SymLink),
+        _ => Err(CatError::UnknownFiletype {
+            ft_debug: format!("{:?}", ft),
+        }),
+    }
+}
+
+/// Writes handle to stdout with no configuration. This allows a
+/// simple memory copy.
+fn write_fast<R: Read>(handle: &mut InputHandle<R>) -> CatResult<()> {
+    let stdout = io::stdout();
+    let mut stdout_lock = stdout.lock();
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    {
+        // If we're on Linux or Android, try to use the splice() system call
+        // for faster writing. If it works, we're done.
+        if !splice::write_fast_using_splice(handle, stdout_lock.as_raw_fd())? {
+            return Ok(());
+        }
+    }
+    // If we're not on Linux or Android, or the splice() call failed,
+    // fall back on slower writing.
+    let mut buf = [0; 1024 * 64];
+    while let Ok(n) = handle.reader.read(&mut buf) {
+        if n == 0 {
+            break;
+        }
+        stdout_lock.write_all(&buf[..n])?;
+    }
+    Ok(())
+}
+
+/// Outputs file contents to stdout in a line-by-line fashion,
+/// propagating any errors that might occur.
+fn write_lines<R: Read>(
+    handle: &mut InputHandle<R>,
+    options: &OutputOptions,
+    state: &mut OutputState,
+) -> CatResult<()> {
+    let mut in_buf = [0; 1024 * 31];
+    let stdout = io::stdout();
+    let mut writer = stdout.lock();
+
+    while let Ok(n) = handle.reader.read(&mut in_buf) {
+        if n == 0 {
+            break;
+        }
+        let in_buf = &in_buf[..n];
+        let mut pos = 0;
+        while pos < n {
+            // skip empty line_number enumerating them if needed
+            if in_buf[pos] == b'\n' {
+                // \r followed by \n is printed as ^M when show_ends is enabled, so that \r\n prints as ^M$
+                if state.skipped_carriage_return && options.show_ends {
+                    writer.write_all(b"^M")?;
+                    state.skipped_carriage_return = false;
+                }
+                if !state.at_line_start || !options.squeeze_blank || !state.one_blank_kept {
+                    state.one_blank_kept = true;
+                    if state.at_line_start && options.number == NumberingMode::All {
+                        write!(&mut writer, "{0:6}\t", state.line_number)?;
+                        state.line_number += 1;
+                    }
+                    writer.write_all(options.end_of_line().as_bytes())?;
+                    if handle.is_interactive {
+                        writer.flush()?;
+                    }
+                }
+                state.at_line_start = true;
+                pos += 1;
+                continue;
+            }
+            if state.skipped_carriage_return {
+                writer.write_all(b"\r")?;
+                state.skipped_carriage_return = false;
+                state.at_line_start = false;
+            }
+            state.one_blank_kept = false;
+            if state.at_line_start && options.number != NumberingMode::None {
+                write!(&mut writer, "{0:6}\t", state.line_number)?;
+                state.line_number += 1;
+            }
+
+            // print to end of line or end of buffer
+            let offset = if options.show_nonprint {
+                write_nonprint_to_end(&in_buf[pos..], &mut writer, options.tab().as_bytes())
+            } else if options.show_tabs {
+                write_tab_to_end(&in_buf[pos..], &mut writer)
+            } else {
+                write_to_end(&in_buf[pos..], &mut writer)
+            };
+            // end of buffer?
+            if offset + pos == in_buf.len() {
+                state.at_line_start = false;
+                break;
+            }
+            if in_buf[pos + offset] == b'\r' {
+                state.skipped_carriage_return = true;
+            } else {
+                assert_eq!(in_buf[pos + offset], b'\n');
+                // print suitable end of line
+                writer.write_all(options.end_of_line().as_bytes())?;
+                if handle.is_interactive {
+                    writer.flush()?;
+                }
+                state.at_line_start = true;
+            }
+            pos += offset + 1;
+        }
+    }
+
+    Ok(())
+}
+
+// write***_to_end methods
+// Write all symbols till \n or \r or end of buffer is reached
+// We need to stop at \r because it may be written as ^M depending on the byte after and settings;
+// however, write_nonprint_to_end doesn't need to stop at \r because it will always write \r as ^M.
+// Return the number of written symbols
+fn write_to_end<W: Write>(in_buf: &[u8], writer: &mut W) -> usize {
+    match in_buf.iter().position(|c| *c == b'\n' || *c == b'\r') {
+        Some(p) => {
+            writer.write_all(&in_buf[..p]).unwrap();
+            p
+        }
+        None => {
+            writer.write_all(in_buf).unwrap();
+            in_buf.len()
+        }
+    }
+}
+
+fn write_tab_to_end<W: Write>(mut in_buf: &[u8], writer: &mut W) -> usize {
+    let mut count = 0;
+    loop {
+        match in_buf
+            .iter()
+            .position(|c| *c == b'\n' || *c == b'\t' || *c == b'\r')
+        {
+            Some(p) => {
+                writer.write_all(&in_buf[..p]).unwrap();
+                if in_buf[p] == b'\n' {
+                    return count + p;
+                } else if in_buf[p] == b'\t' {
+                    writer.write_all(b"^I").unwrap();
+                    in_buf = &in_buf[p + 1..];
+                    count += p + 1;
+                } else {
+                    return count + p;
+                }
+            }
+            None => {
+                writer.write_all(in_buf).unwrap();
+                return in_buf.len();
+            }
+        };
+    }
+}
+
+fn write_nonprint_to_end<W: Write>(in_buf: &[u8], writer: &mut W, tab: &[u8]) -> usize {
+    let mut count = 0;
+
+    for byte in in_buf.iter().map(|c| *c) {
+        if byte == b'\n' {
+            break;
+        }
+        match byte {
+            9 => writer.write_all(tab),
+            0..=8 | 10..=31 => writer.write_all(&[b'^', byte + 64]),
+            32..=126 => writer.write_all(&[byte]),
+            127 => writer.write_all(&[b'^', byte - 64]),
+            128..=159 => writer.write_all(&[b'M', b'-', b'^', byte - 64]),
+            160..=254 => writer.write_all(&[b'M', b'-', byte - 128]),
+            _ => writer.write_all(&[b'M', b'-', b'^', 63]),
+        }
+        .unwrap();
+        count += 1;
+    }
+    count
+}
+
+#[cfg(test)]
+mod tests {
+    use std::io::{stdout, BufWriter};
+
+    #[test]
+    fn test_write_nonprint_to_end_new_line() {
+        let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
+        let in_buf = b"\n";
+        let tab = b"";
+        super::write_nonprint_to_end(in_buf, &mut writer, tab);
+        assert_eq!(writer.buffer().len(), 0);
+    }
+
+    #[test]
+    fn test_write_nonprint_to_end_9() {
+        let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
+        let in_buf = &[9u8];
+        let tab = b"tab";
+        super::write_nonprint_to_end(in_buf, &mut writer, tab);
+        assert_eq!(writer.buffer(), tab);
+    }
+
+    #[test]
+    fn test_write_nonprint_to_end_0_to_8() {
+        for byte in 0u8..=8u8 {
+            let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
+            let in_buf = &[byte];
+            let tab = b"";
+            super::write_nonprint_to_end(in_buf, &mut writer, tab);
+            assert_eq!(writer.buffer(), [b'^', byte + 64]);
+        }
+    }
+
+    #[test]
+    fn test_write_nonprint_to_end_10_to_31() {
+        for byte in 11u8..=31u8 {
+            let mut writer = BufWriter::with_capacity(1024 * 64, stdout());
+            let in_buf = &[byte];
+            let tab = b"";
+            super::write_nonprint_to_end(in_buf, &mut writer, tab);
+            assert_eq!(writer.buffer(), [b'^', byte + 64]);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_cat/splice.rs.html b/src/uu_cat/splice.rs.html new file mode 100644 index 000000000..3c47fd5db --- /dev/null +++ b/src/uu_cat/splice.rs.html @@ -0,0 +1,185 @@ +splice.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+
+use super::{CatResult, InputHandle};
+
+use nix::fcntl::{splice, SpliceFFlags};
+use nix::unistd::{self, pipe};
+use std::fs::File;
+use std::io::Read;
+use std::os::unix::io::{FromRawFd, RawFd};
+
+const BUF_SIZE: usize = 1024 * 16;
+
+/// This function is called from `write_fast()` on Linux and Android. The
+/// function `splice()` is used to move data between two file descriptors
+/// without copying between kernel and user spaces. This results in a large
+/// speedup.
+///
+/// The `bool` in the result value indicates if we need to fall back to normal
+/// copying or not. False means we don't have to.
+#[inline]
+pub(super) fn write_fast_using_splice<R: Read>(
+    handle: &mut InputHandle<R>,
+    write_fd: RawFd,
+) -> CatResult<bool> {
+    let (pipe_rd, pipe_wr) = pipe()?;
+
+    // Ensure the pipe is closed when the function returns.
+    // SAFETY: The file descriptors do not have other owners.
+    let _handles = unsafe { (File::from_raw_fd(pipe_rd), File::from_raw_fd(pipe_wr)) };
+
+    loop {
+        match splice(
+            handle.file_descriptor,
+            None,
+            pipe_wr,
+            None,
+            BUF_SIZE,
+            SpliceFFlags::empty(),
+        ) {
+            Ok(n) => {
+                if n == 0 {
+                    return Ok(false);
+                }
+                if splice_exact(pipe_rd, write_fd, n).is_err() {
+                    // If the first splice manages to copy to the intermediate
+                    // pipe, but the second splice to stdout fails for some reason
+                    // we can recover by copying the data that we have from the
+                    // intermediate pipe to stdout using normal read/write. Then
+                    // we tell the caller to fall back.
+                    copy_exact(pipe_rd, write_fd, n)?;
+                    return Ok(true);
+                }
+            }
+            Err(_) => {
+                return Ok(true);
+            }
+        }
+    }
+}
+
+/// Splice wrapper which handles short writes.
+#[inline]
+fn splice_exact(read_fd: RawFd, write_fd: RawFd, num_bytes: usize) -> nix::Result<()> {
+    let mut left = num_bytes;
+    loop {
+        let written = splice(read_fd, None, write_fd, None, left, SpliceFFlags::empty())?;
+        left -= written;
+        if left == 0 {
+            break;
+        }
+    }
+    Ok(())
+}
+
+/// Caller must ensure that `num_bytes <= BUF_SIZE`, otherwise this function
+/// will panic. The way we use this function in `write_fast_using_splice`
+/// above is safe because `splice` is set to write at most `BUF_SIZE` to the
+/// pipe.
+#[inline]
+fn copy_exact(read_fd: RawFd, write_fd: RawFd, num_bytes: usize) -> nix::Result<()> {
+    let mut left = num_bytes;
+    let mut buf = [0; BUF_SIZE];
+    loop {
+        let read = unistd::read(read_fd, &mut buf[..left])?;
+        let written = unistd::write(write_fd, &buf[..read])?;
+        left -= written;
+        if left == 0 {
+            break;
+        }
+    }
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_chcon/chcon.rs.html b/src/uu_chcon/chcon.rs.html new file mode 100644 index 000000000..02a1f2d44 --- /dev/null +++ b/src/uu_chcon/chcon.rs.html @@ -0,0 +1,1505 @@ +chcon.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+
+// spell-checker:ignore (vars) RFILE
+
+#![allow(clippy::upper_case_acronyms)]
+
+use uucore::{show_error, show_usage_error, show_warning};
+
+use clap::{App, Arg};
+use selinux::{OpaqueSecurityContext, SecurityContext};
+
+use std::borrow::Cow;
+use std::ffi::{CStr, CString, OsStr, OsString};
+use std::os::raw::c_int;
+use std::path::{Path, PathBuf};
+use std::{fs, io};
+
+mod errors;
+mod fts;
+
+use errors::*;
+
+static VERSION: &str = env!("CARGO_PKG_VERSION");
+static ABOUT: &str = "Change the SELinux security context of each FILE to CONTEXT. \n\
+                      With --reference, change the security context of each FILE to that of RFILE.";
+
+pub mod options {
+    pub static VERBOSE: &str = "verbose";
+
+    pub static REFERENCE: &str = "reference";
+
+    pub static USER: &str = "user";
+    pub static ROLE: &str = "role";
+    pub static TYPE: &str = "type";
+    pub static RANGE: &str = "range";
+
+    pub static RECURSIVE: &str = "recursive";
+
+    pub mod sym_links {
+        pub static FOLLOW_ARG_DIR_SYM_LINK: &str = "follow-arg-dir-sym-link";
+        pub static FOLLOW_DIR_SYM_LINKS: &str = "follow-dir-sym-links";
+        pub static NO_FOLLOW_SYM_LINKS: &str = "no-follow-sym-links";
+    }
+
+    pub mod dereference {
+        pub static DEREFERENCE: &str = "dereference";
+        pub static NO_DEREFERENCE: &str = "no-dereference";
+    }
+
+    pub mod preserve_root {
+        pub static PRESERVE_ROOT: &str = "preserve-root";
+        pub static NO_PRESERVE_ROOT: &str = "no-preserve-root";
+    }
+}
+
+fn get_usage() -> String {
+    format!(
+        "{0} [OPTION]... CONTEXT FILE... \n    \
+         {0} [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE... \n    \
+         {0} [OPTION]... --reference=RFILE FILE...",
+        uucore::execution_phrase()
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = get_usage();
+
+    let config = uu_app().usage(usage.as_ref());
+
+    let options = match parse_command_line(config, args) {
+        Ok(r) => r,
+        Err(r) => {
+            if let Error::CommandLine(r) = &r {
+                match r.kind {
+                    clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => {
+                        println!("{}", r);
+                        return libc::EXIT_SUCCESS;
+                    }
+                    _ => {}
+                }
+            }
+
+            show_usage_error!("{}.\n", r);
+            return libc::EXIT_FAILURE;
+        }
+    };
+
+    let context = match &options.mode {
+        CommandLineMode::ReferenceBased { reference } => {
+            let result = match SecurityContext::of_path(reference, true, false) {
+                Ok(Some(context)) => Ok(context),
+
+                Ok(None) => {
+                    let err = io::Error::from_raw_os_error(libc::ENODATA);
+                    Err(Error::from_io1("Getting security context", reference, err))
+                }
+
+                Err(r) => Err(Error::from_selinux("Getting security context", r)),
+            };
+
+            match result {
+                Err(r) => {
+                    show_error!("{}.", report_full_error(&r));
+                    return libc::EXIT_FAILURE;
+                }
+
+                Ok(file_context) => SELinuxSecurityContext::File(file_context),
+            }
+        }
+
+        CommandLineMode::ContextBased { context } => {
+            let c_context = match os_str_to_c_string(context) {
+                Ok(context) => context,
+
+                Err(_r) => {
+                    show_error!("Invalid security context '{}'.", context.to_string_lossy());
+                    return libc::EXIT_FAILURE;
+                }
+            };
+
+            if SecurityContext::from_c_str(&c_context, false).check() == Some(false) {
+                show_error!("Invalid security context '{}'.", context.to_string_lossy());
+                return libc::EXIT_FAILURE;
+            }
+
+            SELinuxSecurityContext::String(Some(c_context))
+        }
+
+        CommandLineMode::Custom { .. } => SELinuxSecurityContext::String(None),
+    };
+
+    let root_dev_ino = if options.preserve_root && options.recursive_mode.is_recursive() {
+        match get_root_dev_ino() {
+            Ok(r) => Some(r),
+
+            Err(r) => {
+                show_error!("{}.", report_full_error(&r));
+                return libc::EXIT_FAILURE;
+            }
+        }
+    } else {
+        None
+    };
+
+    let results = process_files(&options, &context, root_dev_ino);
+    if results.is_empty() {
+        return libc::EXIT_SUCCESS;
+    }
+
+    for result in &results {
+        show_error!("{}.", report_full_error(result));
+    }
+    libc::EXIT_FAILURE
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(VERSION)
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::dereference::DEREFERENCE)
+                .long(options::dereference::DEREFERENCE)
+                .conflicts_with(options::dereference::NO_DEREFERENCE)
+                .help(
+                    "Affect the referent of each symbolic link (this is the default), \
+                     rather than the symbolic link itself.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::dereference::NO_DEREFERENCE)
+                .short("h")
+                .long(options::dereference::NO_DEREFERENCE)
+                .help("Affect symbolic links instead of any referenced file."),
+        )
+        .arg(
+            Arg::with_name(options::preserve_root::PRESERVE_ROOT)
+                .long(options::preserve_root::PRESERVE_ROOT)
+                .conflicts_with(options::preserve_root::NO_PRESERVE_ROOT)
+                .help("Fail to operate recursively on '/'."),
+        )
+        .arg(
+            Arg::with_name(options::preserve_root::NO_PRESERVE_ROOT)
+                .long(options::preserve_root::NO_PRESERVE_ROOT)
+                .help("Do not treat '/' specially (the default)."),
+        )
+        .arg(
+            Arg::with_name(options::REFERENCE)
+                .long(options::REFERENCE)
+                .takes_value(true)
+                .value_name("RFILE")
+                .conflicts_with_all(&[options::USER, options::ROLE, options::TYPE, options::RANGE])
+                .help(
+                    "Use security context of RFILE, rather than specifying \
+                     a CONTEXT value.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::USER)
+                .short("u")
+                .long(options::USER)
+                .takes_value(true)
+                .value_name("USER")
+                .help("Set user USER in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::ROLE)
+                .short("r")
+                .long(options::ROLE)
+                .takes_value(true)
+                .value_name("ROLE")
+                .help("Set role ROLE in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::TYPE)
+                .short("t")
+                .long(options::TYPE)
+                .takes_value(true)
+                .value_name("TYPE")
+                .help("Set type TYPE in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::RANGE)
+                .short("l")
+                .long(options::RANGE)
+                .takes_value(true)
+                .value_name("RANGE")
+                .help("Set range RANGE in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::RECURSIVE)
+                .short("R")
+                .long(options::RECURSIVE)
+                .help("Operate on files and directories recursively."),
+        )
+        .arg(
+            Arg::with_name(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK)
+                .short("H")
+                .requires(options::RECURSIVE)
+                .overrides_with_all(&[
+                    options::sym_links::FOLLOW_DIR_SYM_LINKS,
+                    options::sym_links::NO_FOLLOW_SYM_LINKS,
+                ])
+                .help(
+                    "If a command line argument is a symbolic link to a directory, \
+                     traverse it. Only valid when -R is specified.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::sym_links::FOLLOW_DIR_SYM_LINKS)
+                .short("L")
+                .requires(options::RECURSIVE)
+                .overrides_with_all(&[
+                    options::sym_links::FOLLOW_ARG_DIR_SYM_LINK,
+                    options::sym_links::NO_FOLLOW_SYM_LINKS,
+                ])
+                .help(
+                    "Traverse every symbolic link to a directory encountered. \
+                     Only valid when -R is specified.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::sym_links::NO_FOLLOW_SYM_LINKS)
+                .short("P")
+                .requires(options::RECURSIVE)
+                .overrides_with_all(&[
+                    options::sym_links::FOLLOW_ARG_DIR_SYM_LINK,
+                    options::sym_links::FOLLOW_DIR_SYM_LINKS,
+                ])
+                .help(
+                    "Do not traverse any symbolic links (default). \
+                     Only valid when -R is specified.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE)
+                .short("v")
+                .long(options::VERBOSE)
+                .help("Output a diagnostic for every file processed."),
+        )
+        .arg(Arg::with_name("FILE").multiple(true).min_values(1))
+}
+
+#[derive(Debug)]
+struct Options {
+    verbose: bool,
+    dereference: bool,
+    preserve_root: bool,
+    recursive_mode: RecursiveMode,
+    affect_symlink_referent: bool,
+    mode: CommandLineMode,
+    files: Vec<PathBuf>,
+}
+
+fn parse_command_line(config: clap::App, args: impl uucore::Args) -> Result<Options> {
+    let matches = config.get_matches_from_safe(args)?;
+
+    let verbose = matches.is_present(options::VERBOSE);
+
+    let (recursive_mode, affect_symlink_referent) = if matches.is_present(options::RECURSIVE) {
+        if matches.is_present(options::sym_links::FOLLOW_DIR_SYM_LINKS) {
+            if matches.is_present(options::dereference::NO_DEREFERENCE) {
+                return Err(Error::ArgumentsMismatch(format!(
+                    "'--{}' with '--{}' require '-P'",
+                    options::RECURSIVE,
+                    options::dereference::NO_DEREFERENCE
+                )));
+            }
+
+            (RecursiveMode::RecursiveAndFollowAllDirSymLinks, true)
+        } else if matches.is_present(options::sym_links::FOLLOW_ARG_DIR_SYM_LINK) {
+            if matches.is_present(options::dereference::NO_DEREFERENCE) {
+                return Err(Error::ArgumentsMismatch(format!(
+                    "'--{}' with '--{}' require '-P'",
+                    options::RECURSIVE,
+                    options::dereference::NO_DEREFERENCE
+                )));
+            }
+
+            (RecursiveMode::RecursiveAndFollowArgDirSymLinks, true)
+        } else {
+            if matches.is_present(options::dereference::DEREFERENCE) {
+                return Err(Error::ArgumentsMismatch(format!(
+                    "'--{}' with '--{}' require either '-H' or '-L'",
+                    options::RECURSIVE,
+                    options::dereference::DEREFERENCE
+                )));
+            }
+
+            (RecursiveMode::RecursiveButDoNotFollowSymLinks, false)
+        }
+    } else {
+        let no_dereference = matches.is_present(options::dereference::NO_DEREFERENCE);
+        (RecursiveMode::NotRecursive, !no_dereference)
+    };
+
+    // By default, dereference.
+    let dereference = !matches.is_present(options::dereference::NO_DEREFERENCE);
+
+    // By default, do not preserve root.
+    let preserve_root = matches.is_present(options::preserve_root::PRESERVE_ROOT);
+
+    let mut files = matches.values_of_os("FILE").unwrap_or_default();
+
+    let mode = if let Some(path) = matches.value_of_os(options::REFERENCE) {
+        CommandLineMode::ReferenceBased {
+            reference: PathBuf::from(path),
+        }
+    } else if matches.is_present(options::USER)
+        || matches.is_present(options::ROLE)
+        || matches.is_present(options::TYPE)
+        || matches.is_present(options::RANGE)
+    {
+        CommandLineMode::Custom {
+            user: matches.value_of_os(options::USER).map(Into::into),
+            role: matches.value_of_os(options::ROLE).map(Into::into),
+            the_type: matches.value_of_os(options::TYPE).map(Into::into),
+            range: matches.value_of_os(options::RANGE).map(Into::into),
+        }
+    } else if let Some(context) = files.next() {
+        CommandLineMode::ContextBased {
+            context: context.into(),
+        }
+    } else {
+        return Err(Error::MissingContext);
+    };
+
+    let files: Vec<_> = files.map(PathBuf::from).collect();
+    if files.is_empty() {
+        return Err(Error::MissingFiles);
+    }
+
+    Ok(Options {
+        verbose,
+        dereference,
+        preserve_root,
+        recursive_mode,
+        affect_symlink_referent,
+        mode,
+        files,
+    })
+}
+
+#[derive(Debug, Copy, Clone)]
+enum RecursiveMode {
+    NotRecursive,
+    /// Do not traverse any symbolic links.
+    RecursiveButDoNotFollowSymLinks,
+    /// Traverse every symbolic link to a directory encountered.
+    RecursiveAndFollowAllDirSymLinks,
+    /// If a command line argument is a symbolic link to a directory, traverse it.
+    RecursiveAndFollowArgDirSymLinks,
+}
+
+impl RecursiveMode {
+    fn is_recursive(self) -> bool {
+        match self {
+            RecursiveMode::NotRecursive => false,
+
+            RecursiveMode::RecursiveButDoNotFollowSymLinks
+            | RecursiveMode::RecursiveAndFollowAllDirSymLinks
+            | RecursiveMode::RecursiveAndFollowArgDirSymLinks => true,
+        }
+    }
+
+    fn fts_open_options(self) -> c_int {
+        match self {
+            RecursiveMode::NotRecursive | RecursiveMode::RecursiveButDoNotFollowSymLinks => {
+                fts_sys::FTS_PHYSICAL
+            }
+
+            RecursiveMode::RecursiveAndFollowAllDirSymLinks => fts_sys::FTS_LOGICAL,
+
+            RecursiveMode::RecursiveAndFollowArgDirSymLinks => {
+                fts_sys::FTS_PHYSICAL | fts_sys::FTS_COMFOLLOW
+            }
+        }
+    }
+}
+
+#[derive(Debug)]
+enum CommandLineMode {
+    ReferenceBased {
+        reference: PathBuf,
+    },
+    ContextBased {
+        context: OsString,
+    },
+    Custom {
+        user: Option<OsString>,
+        role: Option<OsString>,
+        the_type: Option<OsString>,
+        range: Option<OsString>,
+    },
+}
+
+fn process_files(
+    options: &Options,
+    context: &SELinuxSecurityContext,
+    root_dev_ino: Option<(libc::ino_t, libc::dev_t)>,
+) -> Vec<Error> {
+    let fts_options = options.recursive_mode.fts_open_options();
+    let mut fts = match fts::FTS::new(options.files.iter(), fts_options) {
+        Ok(fts) => fts,
+        Err(err) => return vec![err],
+    };
+
+    let mut errors = Vec::default();
+    loop {
+        match fts.read_next_entry() {
+            Ok(true) => {
+                if let Err(err) = process_file(options, context, &mut fts, root_dev_ino) {
+                    errors.push(err);
+                }
+            }
+
+            Ok(false) => break,
+
+            Err(err) => {
+                errors.push(err);
+                break;
+            }
+        }
+    }
+    errors
+}
+
+fn process_file(
+    options: &Options,
+    context: &SELinuxSecurityContext,
+    fts: &mut fts::FTS,
+    root_dev_ino: Option<(libc::ino_t, libc::dev_t)>,
+) -> Result<()> {
+    let mut entry = fts.last_entry_ref().unwrap();
+
+    let file_full_name = entry.path().map(PathBuf::from).ok_or_else(|| {
+        Error::from_io("File name validation", io::ErrorKind::InvalidInput.into())
+    })?;
+
+    let fts_access_path = entry.access_path().ok_or_else(|| {
+        let err = io::ErrorKind::InvalidInput.into();
+        Error::from_io1("File name validation", &file_full_name, err)
+    })?;
+
+    let err = |s, k: io::ErrorKind| Error::from_io1(s, &file_full_name, k.into());
+
+    let fts_err = |s| {
+        let r = io::Error::from_raw_os_error(entry.errno());
+        Err(Error::from_io1(s, &file_full_name, r))
+    };
+
+    // SAFETY: If `entry.fts_statp` is not null, then is is assumed to be valid.
+    let file_dev_ino = if let Some(stat) = entry.stat() {
+        (stat.st_ino, stat.st_dev)
+    } else {
+        return Err(err("Getting meta data", io::ErrorKind::InvalidInput));
+    };
+
+    let mut result = Ok(());
+
+    match entry.flags() {
+        fts_sys::FTS_D => {
+            if options.recursive_mode.is_recursive() {
+                if root_dev_ino_check(root_dev_ino, file_dev_ino) {
+                    // This happens e.g., with "chcon -R --preserve-root ... /"
+                    // and with "chcon -RH --preserve-root ... symlink-to-root".
+                    root_dev_ino_warn(&file_full_name);
+
+                    // Tell fts not to traverse into this hierarchy.
+                    let _ignored = fts.set(fts_sys::FTS_SKIP);
+
+                    // Ensure that we do not process "/" on the second visit.
+                    let _ignored = fts.read_next_entry();
+
+                    return Err(err("Modifying root path", io::ErrorKind::PermissionDenied));
+                }
+
+                return Ok(());
+            }
+        }
+
+        fts_sys::FTS_DP => {
+            if !options.recursive_mode.is_recursive() {
+                return Ok(());
+            }
+        }
+
+        fts_sys::FTS_NS => {
+            // For a top-level file or directory, this FTS_NS (stat failed) indicator is determined
+            // at the time of the initial fts_open call. With programs like chmod, chown, and chgrp,
+            // that modify permissions, it is possible that the file in question is accessible when
+            // control reaches this point. So, if this is the first time we've seen the FTS_NS for
+            // this file, tell fts_read to stat it "again".
+            if entry.level() == 0 && entry.number() == 0 {
+                entry.set_number(1);
+                let _ignored = fts.set(fts_sys::FTS_AGAIN);
+                return Ok(());
+            }
+
+            result = fts_err("Accessing");
+        }
+
+        fts_sys::FTS_ERR => result = fts_err("Accessing"),
+
+        fts_sys::FTS_DNR => result = fts_err("Reading directory"),
+
+        fts_sys::FTS_DC => {
+            if cycle_warning_required(options.recursive_mode.fts_open_options(), &entry) {
+                emit_cycle_warning(&file_full_name);
+                return Err(err("Reading cyclic directory", io::ErrorKind::InvalidData));
+            }
+        }
+
+        _ => {}
+    }
+
+    if entry.flags() == fts_sys::FTS_DP
+        && result.is_ok()
+        && root_dev_ino_check(root_dev_ino, file_dev_ino)
+    {
+        root_dev_ino_warn(&file_full_name);
+        result = Err(err("Modifying root path", io::ErrorKind::PermissionDenied));
+    }
+
+    if result.is_ok() {
+        if options.verbose {
+            println!(
+                "{}: Changing security context of: {}",
+                uucore::util_name(),
+                file_full_name.to_string_lossy()
+            );
+        }
+
+        result = change_file_context(options, context, fts_access_path);
+    }
+
+    if !options.recursive_mode.is_recursive() {
+        let _ignored = fts.set(fts_sys::FTS_SKIP);
+    }
+    result
+}
+
+fn change_file_context(
+    options: &Options,
+    context: &SELinuxSecurityContext,
+    path: &Path,
+) -> Result<()> {
+    match &options.mode {
+        CommandLineMode::Custom {
+            user,
+            role,
+            the_type,
+            range,
+        } => {
+            let err0 = || -> Result<()> {
+                // If the file doesn't have a context, and we're not setting all of the context
+                // components, there isn't really an obvious default. Thus, we just give up.
+                let op = "Applying partial security context to unlabeled file";
+                let err = io::ErrorKind::InvalidInput.into();
+                Err(Error::from_io1(op, path, err))
+            };
+
+            let file_context =
+                match SecurityContext::of_path(path, options.affect_symlink_referent, false) {
+                    Ok(Some(context)) => context,
+
+                    Ok(None) => return err0(),
+                    Err(r) => return Err(Error::from_selinux("Getting security context", r)),
+                };
+
+            let c_file_context = match file_context.to_c_string() {
+                Ok(Some(context)) => context,
+
+                Ok(None) => return err0(),
+                Err(r) => return Err(Error::from_selinux("Getting security context", r)),
+            };
+
+            let se_context =
+                OpaqueSecurityContext::from_c_str(c_file_context.as_ref()).map_err(|_r| {
+                    let err = io::ErrorKind::InvalidInput.into();
+                    Error::from_io1("Creating security context", path, err)
+                })?;
+
+            type SetValueProc = fn(&OpaqueSecurityContext, &CStr) -> selinux::errors::Result<()>;
+
+            let list: &[(&Option<OsString>, SetValueProc)] = &[
+                (user, OpaqueSecurityContext::set_user),
+                (role, OpaqueSecurityContext::set_role),
+                (the_type, OpaqueSecurityContext::set_type),
+                (range, OpaqueSecurityContext::set_range),
+            ];
+
+            for (new_value, set_value_proc) in list {
+                if let Some(new_value) = new_value {
+                    let c_new_value = os_str_to_c_string(new_value).map_err(|_r| {
+                        let err = io::ErrorKind::InvalidInput.into();
+                        Error::from_io1("Creating security context", path, err)
+                    })?;
+
+                    set_value_proc(&se_context, &c_new_value)
+                        .map_err(|r| Error::from_selinux("Setting security context user", r))?;
+                }
+            }
+
+            let context_string = se_context
+                .to_c_string()
+                .map_err(|r| Error::from_selinux("Getting security context", r))?;
+
+            if c_file_context.as_ref().to_bytes() == context_string.as_ref().to_bytes() {
+                Ok(()) // Nothing to change.
+            } else {
+                SecurityContext::from_c_str(&context_string, false)
+                    .set_for_path(path, options.affect_symlink_referent, false)
+                    .map_err(|r| Error::from_selinux("Setting security context", r))
+            }
+        }
+
+        CommandLineMode::ReferenceBased { .. } | CommandLineMode::ContextBased { .. } => {
+            if let Some(c_context) = context.to_c_string()? {
+                SecurityContext::from_c_str(c_context.as_ref(), false)
+                    .set_for_path(path, options.affect_symlink_referent, false)
+                    .map_err(|r| Error::from_selinux("Setting security context", r))
+            } else {
+                let err = io::ErrorKind::InvalidInput.into();
+                Err(Error::from_io1("Setting security context", path, err))
+            }
+        }
+    }
+}
+
+#[cfg(unix)]
+pub(crate) fn os_str_to_c_string(s: &OsStr) -> Result<CString> {
+    use std::os::unix::ffi::OsStrExt;
+
+    CString::new(s.as_bytes())
+        .map_err(|_r| Error::from_io("CString::new()", io::ErrorKind::InvalidInput.into()))
+}
+
+/// Call `lstat()` to get the device and inode numbers for `/`.
+#[cfg(unix)]
+fn get_root_dev_ino() -> Result<(libc::ino_t, libc::dev_t)> {
+    use std::os::unix::fs::MetadataExt;
+
+    fs::symlink_metadata("/")
+        .map(|md| (md.ino(), md.dev()))
+        .map_err(|r| Error::from_io1("std::fs::symlink_metadata", "/", r))
+}
+
+fn root_dev_ino_check(
+    root_dev_ino: Option<(libc::ino_t, libc::dev_t)>,
+    dir_dev_ino: (libc::ino_t, libc::dev_t),
+) -> bool {
+    root_dev_ino.map_or(false, |root_dev_ino| root_dev_ino == dir_dev_ino)
+}
+
+fn root_dev_ino_warn(dir_name: &Path) {
+    if dir_name.as_os_str() == "/" {
+        show_warning!(
+            "It is dangerous to operate recursively on '/'. \
+             Use --{} to override this failsafe.",
+            options::preserve_root::NO_PRESERVE_ROOT,
+        );
+    } else {
+        show_warning!(
+            "It is dangerous to operate recursively on '{}' (same as '/'). \
+             Use --{} to override this failsafe.",
+            dir_name.to_string_lossy(),
+            options::preserve_root::NO_PRESERVE_ROOT,
+        );
+    }
+}
+
+// When fts_read returns FTS_DC to indicate a directory cycle, it may or may not indicate
+// a real problem.
+// When a program like chgrp performs a recursive traversal that requires traversing symbolic links,
+// it is *not* a problem.
+// However, when invoked with "-P -R", it deserves a warning.
+// The fts_options parameter records the options that control this aspect of fts's behavior,
+// so test that.
+fn cycle_warning_required(fts_options: c_int, entry: &fts::EntryRef) -> bool {
+    // When dereferencing no symlinks, or when dereferencing only those listed on the command line
+    // and we're not processing a command-line argument, then a cycle is a serious problem.
+    ((fts_options & fts_sys::FTS_PHYSICAL) != 0)
+        && (((fts_options & fts_sys::FTS_COMFOLLOW) == 0) || entry.level() != 0)
+}
+
+fn emit_cycle_warning(file_name: &Path) {
+    show_warning!(
+        "Circular directory structure.\n\
+This almost certainly means that you have a corrupted file system.\n\
+NOTIFY YOUR SYSTEM MANAGER.\n\
+The following directory is part of the cycle '{}'.",
+        file_name.display()
+    )
+}
+
+#[derive(Debug)]
+enum SELinuxSecurityContext<'t> {
+    File(SecurityContext<'t>),
+    String(Option<CString>),
+}
+
+impl<'t> SELinuxSecurityContext<'t> {
+    fn to_c_string(&self) -> Result<Option<Cow<CStr>>> {
+        match self {
+            Self::File(context) => context
+                .to_c_string()
+                .map_err(|r| Error::from_selinux("SELinuxSecurityContext::to_c_string()", r)),
+
+            Self::String(context) => Ok(context.as_deref().map(Cow::Borrowed)),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_chcon/errors.rs.html b/src/uu_chcon/errors.rs.html new file mode 100644 index 000000000..9e6876cce --- /dev/null +++ b/src/uu_chcon/errors.rs.html @@ -0,0 +1,147 @@ +errors.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+
+use std::ffi::OsString;
+use std::fmt::Write;
+use std::io;
+
+pub(crate) type Result<T> = std::result::Result<T, Error>;
+
+#[derive(thiserror::Error, Debug)]
+pub(crate) enum Error {
+    #[error("No context is specified")]
+    MissingContext,
+
+    #[error("No files are specified")]
+    MissingFiles,
+
+    #[error("{0}")]
+    ArgumentsMismatch(String),
+
+    #[error(transparent)]
+    CommandLine(#[from] clap::Error),
+
+    #[error("{operation} failed")]
+    SELinux {
+        operation: &'static str,
+        source: selinux::errors::Error,
+    },
+
+    #[error("{operation} failed")]
+    Io {
+        operation: &'static str,
+        source: io::Error,
+    },
+
+    #[error("{operation} failed on '{}'", .operand1.to_string_lossy())]
+    Io1 {
+        operation: &'static str,
+        operand1: OsString,
+        source: io::Error,
+    },
+}
+
+impl Error {
+    pub(crate) fn from_io(operation: &'static str, source: io::Error) -> Self {
+        Self::Io { operation, source }
+    }
+
+    pub(crate) fn from_io1(
+        operation: &'static str,
+        operand1: impl Into<OsString>,
+        source: io::Error,
+    ) -> Self {
+        Self::Io1 {
+            operation,
+            operand1: operand1.into(),
+            source,
+        }
+    }
+
+    pub(crate) fn from_selinux(operation: &'static str, source: selinux::errors::Error) -> Self {
+        Self::SELinux { operation, source }
+    }
+}
+
+pub(crate) fn report_full_error(mut err: &dyn std::error::Error) -> String {
+    let mut desc = String::with_capacity(256);
+    write!(&mut desc, "{}", err).unwrap();
+    while let Some(source) = err.source() {
+        err = source;
+        write!(&mut desc, ". {}", err).unwrap();
+    }
+    desc
+}
+
+
\ No newline at end of file diff --git a/src/uu_chcon/fts.rs.html b/src/uu_chcon/fts.rs.html new file mode 100644 index 000000000..d10c649e2 --- /dev/null +++ b/src/uu_chcon/fts.rs.html @@ -0,0 +1,391 @@ +fts.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+
+use std::ffi::{CStr, CString, OsStr};
+use std::marker::PhantomData;
+use std::os::raw::{c_int, c_long, c_short};
+use std::path::Path;
+use std::ptr::NonNull;
+use std::{io, iter, ptr, slice};
+
+use crate::errors::{Error, Result};
+use crate::os_str_to_c_string;
+
+#[derive(Debug)]
+pub(crate) struct FTS {
+    fts: ptr::NonNull<fts_sys::FTS>,
+
+    entry: Option<ptr::NonNull<fts_sys::FTSENT>>,
+    _phantom_data: PhantomData<fts_sys::FTSENT>,
+}
+
+impl FTS {
+    pub(crate) fn new<I>(paths: I, options: c_int) -> Result<Self>
+    where
+        I: IntoIterator,
+        I::Item: AsRef<OsStr>,
+    {
+        let files_paths: Vec<CString> = paths
+            .into_iter()
+            .map(|s| os_str_to_c_string(s.as_ref()))
+            .collect::<Result<_>>()?;
+
+        if files_paths.is_empty() {
+            return Err(Error::from_io(
+                "FTS::new()",
+                io::ErrorKind::InvalidInput.into(),
+            ));
+        }
+
+        let path_argv: Vec<_> = files_paths
+            .iter()
+            .map(CString::as_ref)
+            .map(CStr::as_ptr)
+            .chain(iter::once(ptr::null()))
+            .collect();
+
+        // SAFETY: We assume calling fts_open() is safe:
+        // - `path_argv` is an array holding at least one path, and null-terminated.
+        // - `compar` is None.
+        let fts = unsafe { fts_sys::fts_open(path_argv.as_ptr().cast(), options, None) };
+
+        let fts = ptr::NonNull::new(fts)
+            .ok_or_else(|| Error::from_io("fts_open()", io::Error::last_os_error()))?;
+
+        Ok(Self {
+            fts,
+            entry: None,
+            _phantom_data: PhantomData,
+        })
+    }
+
+    pub(crate) fn last_entry_ref(&mut self) -> Option<EntryRef> {
+        self.entry.map(move |entry| EntryRef::new(self, entry))
+    }
+
+    pub(crate) fn read_next_entry(&mut self) -> Result<bool> {
+        // SAFETY: We assume calling fts_read() is safe with a non-null `fts`
+        // pointer assumed to be valid.
+        let new_entry = unsafe { fts_sys::fts_read(self.fts.as_ptr()) };
+
+        self.entry = NonNull::new(new_entry);
+        if self.entry.is_none() {
+            let r = io::Error::last_os_error();
+            if let Some(0) = r.raw_os_error() {
+                Ok(false)
+            } else {
+                Err(Error::from_io("fts_read()", r))
+            }
+        } else {
+            Ok(true)
+        }
+    }
+
+    pub(crate) fn set(&mut self, instr: c_int) -> Result<()> {
+        let fts = self.fts.as_ptr();
+        let entry = self
+            .entry
+            .ok_or_else(|| Error::from_io("FTS::set()", io::ErrorKind::UnexpectedEof.into()))?;
+
+        // SAFETY: We assume calling fts_set() is safe with non-null `fts`
+        // and `entry` pointers assumed to be valid.
+        if unsafe { fts_sys::fts_set(fts, entry.as_ptr(), instr) } == -1 {
+            Err(Error::from_io("fts_set()", io::Error::last_os_error()))
+        } else {
+            Ok(())
+        }
+    }
+}
+
+impl Drop for FTS {
+    fn drop(&mut self) {
+        // SAFETY: We assume calling fts_close() is safe with a non-null `fts`
+        // pointer assumed to be valid.
+        unsafe { fts_sys::fts_close(self.fts.as_ptr()) };
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct EntryRef<'fts> {
+    pub(crate) pointer: ptr::NonNull<fts_sys::FTSENT>,
+
+    _fts: PhantomData<&'fts FTS>,
+    _phantom_data: PhantomData<fts_sys::FTSENT>,
+}
+
+impl<'fts> EntryRef<'fts> {
+    fn new(_fts: &'fts FTS, entry: ptr::NonNull<fts_sys::FTSENT>) -> Self {
+        Self {
+            pointer: entry,
+            _fts: PhantomData,
+            _phantom_data: PhantomData,
+        }
+    }
+
+    fn as_ref(&self) -> &fts_sys::FTSENT {
+        // SAFETY: `self.pointer` is a non-null pointer that is assumed to be valid.
+        unsafe { self.pointer.as_ref() }
+    }
+
+    fn as_mut(&mut self) -> &mut fts_sys::FTSENT {
+        // SAFETY: `self.pointer` is a non-null pointer that is assumed to be valid.
+        unsafe { self.pointer.as_mut() }
+    }
+
+    pub(crate) fn flags(&self) -> c_int {
+        c_int::from(self.as_ref().fts_info)
+    }
+
+    pub(crate) fn errno(&self) -> c_int {
+        self.as_ref().fts_errno
+    }
+
+    pub(crate) fn level(&self) -> c_short {
+        self.as_ref().fts_level
+    }
+
+    pub(crate) fn number(&self) -> c_long {
+        self.as_ref().fts_number
+    }
+
+    pub(crate) fn set_number(&mut self, new_number: c_long) {
+        self.as_mut().fts_number = new_number;
+    }
+
+    pub(crate) fn path(&self) -> Option<&Path> {
+        let entry = self.as_ref();
+        if entry.fts_pathlen == 0 {
+            return None;
+        }
+
+        NonNull::new(entry.fts_path)
+            .map(|path_ptr| {
+                let path_size = usize::from(entry.fts_pathlen).saturating_add(1);
+
+                // SAFETY: `entry.fts_path` is a non-null pointer that is assumed to be valid.
+                unsafe { slice::from_raw_parts(path_ptr.as_ptr().cast(), path_size) }
+            })
+            .and_then(|bytes| CStr::from_bytes_with_nul(bytes).ok())
+            .map(c_str_to_os_str)
+            .map(Path::new)
+    }
+
+    pub(crate) fn access_path(&self) -> Option<&Path> {
+        ptr::NonNull::new(self.as_ref().fts_accpath)
+            .map(|path_ptr| {
+                // SAFETY: `entry.fts_accpath` is a non-null pointer that is assumed to be valid.
+                unsafe { CStr::from_ptr(path_ptr.as_ptr()) }
+            })
+            .map(c_str_to_os_str)
+            .map(Path::new)
+    }
+
+    pub(crate) fn stat(&self) -> Option<&libc::stat> {
+        ptr::NonNull::new(self.as_ref().fts_statp).map(|stat_ptr| {
+            // SAFETY: `entry.fts_statp` is a non-null pointer that is assumed to be valid.
+            unsafe { stat_ptr.as_ref() }
+        })
+    }
+}
+
+#[cfg(unix)]
+fn c_str_to_os_str(s: &CStr) -> &OsStr {
+    use std::os::unix::ffi::OsStrExt;
+
+    OsStr::from_bytes(s.to_bytes())
+}
+
+
\ No newline at end of file diff --git a/src/uu_chgrp/chgrp.rs.html b/src/uu_chgrp/chgrp.rs.html new file mode 100644 index 000000000..034547669 --- /dev/null +++ b/src/uu_chgrp/chgrp.rs.html @@ -0,0 +1,539 @@ +chgrp.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) COMFOLLOW Chowner RFILE RFILE's derefer dgid nonblank nonprint nonprinting
+
+#[macro_use]
+extern crate uucore;
+pub use uucore::entries;
+use uucore::error::{FromIo, UResult, USimpleError};
+use uucore::perms::{
+    ChownExecutor, IfFrom, Verbosity, VerbosityLevel, FTS_COMFOLLOW, FTS_LOGICAL, FTS_PHYSICAL,
+};
+
+use clap::{App, Arg};
+
+use std::fs;
+use std::os::unix::fs::MetadataExt;
+
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Change the group of each FILE to GROUP.";
+static VERSION: &str = env!("CARGO_PKG_VERSION");
+
+pub mod options {
+    pub mod verbosity {
+        pub static CHANGES: &str = "changes";
+        pub static QUIET: &str = "quiet";
+        pub static SILENT: &str = "silent";
+        pub static VERBOSE: &str = "verbose";
+    }
+    pub mod preserve_root {
+        pub static PRESERVE: &str = "preserve-root";
+        pub static NO_PRESERVE: &str = "no-preserve-root";
+    }
+    pub mod dereference {
+        pub static DEREFERENCE: &str = "dereference";
+        pub static NO_DEREFERENCE: &str = "no-dereference";
+    }
+    pub static RECURSIVE: &str = "recursive";
+    pub mod traverse {
+        pub static TRAVERSE: &str = "H";
+        pub static NO_TRAVERSE: &str = "P";
+        pub static EVERY: &str = "L";
+    }
+    pub static REFERENCE: &str = "reference";
+    pub static ARG_GROUP: &str = "GROUP";
+    pub static ARG_FILES: &str = "FILE";
+}
+
+fn get_usage() -> String {
+    format!(
+        "{0} [OPTION]... GROUP FILE...\n    {0} [OPTION]... --reference=RFILE FILE...",
+        uucore::execution_phrase()
+    )
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let usage = get_usage();
+
+    let mut app = uu_app().usage(&usage[..]);
+
+    // we change the positional args based on whether
+    // --reference was used.
+    let mut reference = false;
+    let mut help = false;
+    // stop processing options on --
+    for arg in args.iter().take_while(|s| *s != "--") {
+        if arg.starts_with("--reference=") || arg == "--reference" {
+            reference = true;
+        } else if arg == "--help" {
+            // we stop processing once we see --help,
+            // as it doesn't matter if we've seen reference or not
+            help = true;
+            break;
+        }
+    }
+
+    if help || !reference {
+        // add both positional arguments
+        app = app.arg(
+            Arg::with_name(options::ARG_GROUP)
+                .value_name(options::ARG_GROUP)
+                .required(true)
+                .takes_value(true)
+                .multiple(false),
+        )
+    }
+    app = app.arg(
+        Arg::with_name(options::ARG_FILES)
+            .value_name(options::ARG_FILES)
+            .multiple(true)
+            .takes_value(true)
+            .required(true)
+            .min_values(1),
+    );
+
+    let matches = app.get_matches_from(args);
+
+    /* Get the list of files */
+    let files: Vec<String> = matches
+        .values_of(options::ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let preserve_root = matches.is_present(options::preserve_root::PRESERVE);
+
+    let mut derefer = if matches.is_present(options::dereference::DEREFERENCE) {
+        1
+    } else if matches.is_present(options::dereference::NO_DEREFERENCE) {
+        0
+    } else {
+        -1
+    };
+
+    let mut bit_flag = if matches.is_present(options::traverse::TRAVERSE) {
+        FTS_COMFOLLOW | FTS_PHYSICAL
+    } else if matches.is_present(options::traverse::EVERY) {
+        FTS_LOGICAL
+    } else {
+        FTS_PHYSICAL
+    };
+
+    let recursive = matches.is_present(options::RECURSIVE);
+    if recursive {
+        if bit_flag == FTS_PHYSICAL {
+            if derefer == 1 {
+                return Err(USimpleError::new(1, "-R --dereference requires -H or -L"));
+            }
+            derefer = 0;
+        }
+    } else {
+        bit_flag = FTS_PHYSICAL;
+    }
+
+    let verbosity_level = if matches.is_present(options::verbosity::CHANGES) {
+        VerbosityLevel::Changes
+    } else if matches.is_present(options::verbosity::SILENT)
+        || matches.is_present(options::verbosity::QUIET)
+    {
+        VerbosityLevel::Silent
+    } else if matches.is_present(options::verbosity::VERBOSE) {
+        VerbosityLevel::Verbose
+    } else {
+        VerbosityLevel::Normal
+    };
+
+    let dest_gid = if let Some(file) = matches.value_of(options::REFERENCE) {
+        fs::metadata(&file)
+            .map(|meta| Some(meta.gid()))
+            .map_err_context(|| format!("failed to get attributes of '{}'", file))?
+    } else {
+        let group = matches.value_of(options::ARG_GROUP).unwrap_or_default();
+        if group.is_empty() {
+            None
+        } else {
+            match entries::grp2gid(group) {
+                Ok(g) => Some(g),
+                _ => return Err(USimpleError::new(1, format!("invalid group: '{}'", group))),
+            }
+        }
+    };
+
+    let executor = ChownExecutor {
+        bit_flag,
+        dest_gid,
+        verbosity: Verbosity {
+            groups_only: true,
+            level: verbosity_level,
+        },
+        recursive,
+        dereference: derefer != 0,
+        preserve_root,
+        files,
+        filter: IfFrom::All,
+        dest_uid: None,
+    };
+    executor.exec()
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(VERSION)
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::verbosity::CHANGES)
+                .short("c")
+                .long(options::verbosity::CHANGES)
+                .help("like verbose but report only when a change is made"),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::SILENT)
+                .short("f")
+                .long(options::verbosity::SILENT),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::QUIET)
+                .long(options::verbosity::QUIET)
+                .help("suppress most error messages"),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::VERBOSE)
+                .short("v")
+                .long(options::verbosity::VERBOSE)
+                .help("output a diagnostic for every file processed"),
+        )
+        .arg(
+            Arg::with_name(options::dereference::DEREFERENCE)
+                .long(options::dereference::DEREFERENCE),
+        )
+        .arg(
+           Arg::with_name(options::dereference::NO_DEREFERENCE)
+               .short("h")
+               .long(options::dereference::NO_DEREFERENCE)
+               .help(
+                   "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
+               ),
+        )
+        .arg(
+            Arg::with_name(options::preserve_root::PRESERVE)
+                .long(options::preserve_root::PRESERVE)
+                .help("fail to operate recursively on '/'"),
+        )
+        .arg(
+            Arg::with_name(options::preserve_root::NO_PRESERVE)
+                .long(options::preserve_root::NO_PRESERVE)
+                .help("do not treat '/' specially (the default)"),
+        )
+        .arg(
+            Arg::with_name(options::REFERENCE)
+                .long(options::REFERENCE)
+                .value_name("RFILE")
+                .help("use RFILE's group rather than specifying GROUP values")
+                .takes_value(true)
+                .multiple(false),
+        )
+        .arg(
+            Arg::with_name(options::RECURSIVE)
+                .short("R")
+                .long(options::RECURSIVE)
+                .help("operate on files and directories recursively"),
+        )
+        .arg(
+            Arg::with_name(options::traverse::TRAVERSE)
+                .short(options::traverse::TRAVERSE)
+                .help("if a command line argument is a symbolic link to a directory, traverse it"),
+        )
+        .arg(
+            Arg::with_name(options::traverse::NO_TRAVERSE)
+                .short(options::traverse::NO_TRAVERSE)
+                .help("do not traverse any symbolic links (default)")
+                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
+        )
+        .arg(
+            Arg::with_name(options::traverse::EVERY)
+                .short(options::traverse::EVERY)
+                .help("traverse every symbolic link to a directory encountered"),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_chmod/chmod.rs.html b/src/uu_chmod/chmod.rs.html new file mode 100644 index 000000000..10b71da90 --- /dev/null +++ b/src/uu_chmod/chmod.rs.html @@ -0,0 +1,717 @@ +chmod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Alex Lyon <arcterus@mail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) Chmoder cmode fmode fperm fref ugoa RFILE RFILE's
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs;
+use std::os::unix::fs::{MetadataExt, PermissionsExt};
+use std::path::Path;
+use uucore::fs::display_permissions_unix;
+use uucore::libc::mode_t;
+#[cfg(not(windows))]
+use uucore::mode;
+use uucore::InvalidEncodingHandling;
+use walkdir::WalkDir;
+
+static ABOUT: &str = "Change the mode of each FILE to MODE.
+ With --reference, change the mode of each FILE to that of RFILE.";
+
+mod options {
+    pub const CHANGES: &str = "changes";
+    pub const QUIET: &str = "quiet"; // visible_alias("silent")
+    pub const VERBOSE: &str = "verbose";
+    pub const NO_PRESERVE_ROOT: &str = "no-preserve-root";
+    pub const PRESERVE_ROOT: &str = "preserve-root";
+    pub const REFERENCE: &str = "RFILE";
+    pub const RECURSIVE: &str = "recursive";
+    pub const MODE: &str = "MODE";
+    pub const FILE: &str = "FILE";
+}
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... MODE[,MODE]... FILE...
+or: {0} [OPTION]... OCTAL-MODE FILE...
+or: {0} [OPTION]... --reference=RFILE FILE...",
+        uucore::execution_phrase()
+    )
+}
+
+fn get_long_usage() -> String {
+    String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let mut args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    // Before we can parse 'args' with clap (and previously getopts),
+    // a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
+    let mode_had_minus_prefix = strip_minus_from_mode(&mut args);
+
+    let usage = usage();
+    let after_help = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let changes = matches.is_present(options::CHANGES);
+    let quiet = matches.is_present(options::QUIET);
+    let verbose = matches.is_present(options::VERBOSE);
+    let preserve_root = matches.is_present(options::PRESERVE_ROOT);
+    let recursive = matches.is_present(options::RECURSIVE);
+    let fmode = matches
+        .value_of(options::REFERENCE)
+        .and_then(|fref| match fs::metadata(fref) {
+            Ok(meta) => Some(meta.mode()),
+            Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err),
+        });
+    let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required
+    let cmode = if mode_had_minus_prefix {
+        // clap parsing is finished, now put prefix back
+        format!("-{}", modes)
+    } else {
+        modes.to_string()
+    };
+    let mut files: Vec<String> = matches
+        .values_of(options::FILE)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+    let cmode = if fmode.is_some() {
+        // "--reference" and MODE are mutually exclusive
+        // if "--reference" was used MODE needs to be interpreted as another FILE
+        // it wasn't possible to implement this behavior directly with clap
+        files.push(cmode);
+        None
+    } else {
+        Some(cmode)
+    };
+
+    let chmoder = Chmoder {
+        changes,
+        quiet,
+        verbose,
+        preserve_root,
+        recursive,
+        fmode,
+        cmode,
+    };
+    match chmoder.chmod(files) {
+        Ok(()) => {}
+        Err(e) => return e,
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::CHANGES)
+                .long(options::CHANGES)
+                .short("c")
+                .help("like verbose but report only when a change is made"),
+        )
+        .arg(
+            Arg::with_name(options::QUIET)
+                .long(options::QUIET)
+                .visible_alias("silent")
+                .short("f")
+                .help("suppress most error messages"),
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE)
+                .long(options::VERBOSE)
+                .short("v")
+                .help("output a diagnostic for every file processed"),
+        )
+        .arg(
+            Arg::with_name(options::NO_PRESERVE_ROOT)
+                .long(options::NO_PRESERVE_ROOT)
+                .help("do not treat '/' specially (the default)"),
+        )
+        .arg(
+            Arg::with_name(options::PRESERVE_ROOT)
+                .long(options::PRESERVE_ROOT)
+                .help("fail to operate recursively on '/'"),
+        )
+        .arg(
+            Arg::with_name(options::RECURSIVE)
+                .long(options::RECURSIVE)
+                .short("R")
+                .help("change files and directories recursively"),
+        )
+        .arg(
+            Arg::with_name(options::REFERENCE)
+                .long("reference")
+                .takes_value(true)
+                .help("use RFILE's mode instead of MODE values"),
+        )
+        .arg(
+            Arg::with_name(options::MODE)
+                .required_unless(options::REFERENCE)
+                .takes_value(true),
+            // It would be nice if clap could parse with delimiter, e.g. "g-x,u+x",
+            // however .multiple(true) cannot be used here because FILE already needs that.
+            // Only one positional argument with .multiple(true) set is allowed per command
+        )
+        .arg(
+            Arg::with_name(options::FILE)
+                .required_unless(options::MODE)
+                .multiple(true),
+        )
+}
+
+// Iterate 'args' and delete the first occurrence
+// of a prefix '-' if it's associated with MODE
+// e.g. "chmod -v -xw -R FILE" -> "chmod -v xw -R FILE"
+pub fn strip_minus_from_mode(args: &mut Vec<String>) -> bool {
+    for arg in args {
+        if arg.starts_with('-') {
+            if let Some(second) = arg.chars().nth(1) {
+                match second {
+                    'r' | 'w' | 'x' | 'X' | 's' | 't' | 'u' | 'g' | 'o' | '0'..='7' => {
+                        // TODO: use strip_prefix() once minimum rust version reaches 1.45.0
+                        *arg = arg[1..arg.len()].to_string();
+                        return true;
+                    }
+                    _ => {}
+                }
+            }
+        }
+    }
+    false
+}
+
+struct Chmoder {
+    changes: bool,
+    quiet: bool,
+    verbose: bool,
+    preserve_root: bool,
+    recursive: bool,
+    fmode: Option<u32>,
+    cmode: Option<String>,
+}
+
+impl Chmoder {
+    fn chmod(&self, files: Vec<String>) -> Result<(), i32> {
+        let mut r = Ok(());
+
+        for filename in &files {
+            let filename = &filename[..];
+            let file = Path::new(filename);
+            if !file.exists() {
+                if is_symlink(file) {
+                    println!(
+                        "failed to change mode of '{}' from 0000 (---------) to 0000 (---------)",
+                        filename
+                    );
+                    if !self.quiet {
+                        show_error!("cannot operate on dangling symlink '{}'", filename);
+                    }
+                } else {
+                    show_error!("cannot access '{}': No such file or directory", filename);
+                }
+                return Err(1);
+            }
+            if self.recursive && self.preserve_root && filename == "/" {
+                show_error!(
+                    "it is dangerous to operate recursively on '{}'\nuse --no-preserve-root to override this failsafe",
+                    filename
+                );
+                return Err(1);
+            }
+            if !self.recursive {
+                r = self.chmod_file(file).and(r);
+            } else {
+                for entry in WalkDir::new(&filename).into_iter().filter_map(|e| e.ok()) {
+                    let file = entry.path();
+                    r = self.chmod_file(file).and(r);
+                }
+            }
+        }
+        r
+    }
+
+    #[cfg(windows)]
+    fn chmod_file(&self, file: &Path) -> Result<(), i32> {
+        // chmod is useless on Windows
+        // it doesn't set any permissions at all
+        // instead it just sets the readonly attribute on the file
+        Err(0)
+    }
+    #[cfg(any(unix, target_os = "redox"))]
+    fn chmod_file(&self, file: &Path) -> Result<(), i32> {
+        let mut fperm = match fs::metadata(file) {
+            Ok(meta) => meta.mode() & 0o7777,
+            Err(err) => {
+                if is_symlink(file) {
+                    if self.verbose {
+                        println!(
+                            "neither symbolic link '{}' nor referent has been changed",
+                            file.display()
+                        );
+                    }
+                    return Ok(());
+                } else if err.kind() == std::io::ErrorKind::PermissionDenied {
+                    show_error!("'{}': Permission denied", file.display());
+                } else {
+                    show_error!("'{}': {}", file.display(), err);
+                }
+                return Err(1);
+            }
+        };
+        match self.fmode {
+            Some(mode) => self.change_file(fperm, mode, file)?,
+            None => {
+                let cmode_unwrapped = self.cmode.clone().unwrap();
+                for mode in cmode_unwrapped.split(',') {
+                    // cmode is guaranteed to be Some in this case
+                    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+                    let result = if mode.contains(arr) {
+                        mode::parse_numeric(fperm, mode)
+                    } else {
+                        mode::parse_symbolic(fperm, mode, file.is_dir())
+                    };
+                    match result {
+                        Ok(mode) => {
+                            self.change_file(fperm, mode, file)?;
+                            fperm = mode;
+                        }
+                        Err(f) => {
+                            if !self.quiet {
+                                show_error!("{}", f);
+                            }
+                            return Err(1);
+                        }
+                    }
+                }
+            }
+        }
+
+        Ok(())
+    }
+
+    #[cfg(unix)]
+    fn change_file(&self, fperm: u32, mode: u32, file: &Path) -> Result<(), i32> {
+        if fperm == mode {
+            if self.verbose && !self.changes {
+                println!(
+                    "mode of '{}' retained as {:04o} ({})",
+                    file.display(),
+                    fperm,
+                    display_permissions_unix(fperm as mode_t, false),
+                );
+            }
+            Ok(())
+        } else if let Err(err) = fs::set_permissions(file, fs::Permissions::from_mode(mode)) {
+            if !self.quiet {
+                show_error!("{}", err);
+            }
+            if self.verbose {
+                show_error!(
+                    "failed to change mode of file '{}' from {:o} ({}) to {:o} ({})",
+                    file.display(),
+                    fperm,
+                    display_permissions_unix(fperm as mode_t, false),
+                    mode,
+                    display_permissions_unix(mode as mode_t, false)
+                );
+            }
+            Err(1)
+        } else {
+            if self.verbose || self.changes {
+                show_error!(
+                    "mode of '{}' changed from {:o} ({}) to {:o} ({})",
+                    file.display(),
+                    fperm,
+                    display_permissions_unix(fperm as mode_t, false),
+                    mode,
+                    display_permissions_unix(mode as mode_t, false)
+                );
+            }
+            Ok(())
+        }
+    }
+}
+
+pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool {
+    match fs::symlink_metadata(path) {
+        Ok(m) => m.file_type().is_symlink(),
+        Err(_) => false,
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_chown/chown.rs.html b/src/uu_chown/chown.rs.html new file mode 100644 index 000000000..7c71ee9af --- /dev/null +++ b/src/uu_chown/chown.rs.html @@ -0,0 +1,591 @@ +chown.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) COMFOLLOW Passwd RFILE RFILE's derefer dgid duid
+
+#[macro_use]
+extern crate uucore;
+pub use uucore::entries::{self, Group, Locate, Passwd};
+use uucore::perms::{
+    ChownExecutor, IfFrom, Verbosity, VerbosityLevel, FTS_COMFOLLOW, FTS_LOGICAL, FTS_PHYSICAL,
+};
+
+use uucore::error::{FromIo, UResult, USimpleError};
+
+use clap::{crate_version, App, Arg};
+
+use std::fs;
+use std::os::unix::fs::MetadataExt;
+
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "change file owner and group";
+
+pub mod options {
+    pub mod verbosity {
+        pub static CHANGES: &str = "changes";
+        pub static QUIET: &str = "quiet";
+        pub static SILENT: &str = "silent";
+        pub static VERBOSE: &str = "verbose";
+    }
+    pub mod preserve_root {
+        pub static PRESERVE: &str = "preserve-root";
+        pub static NO_PRESERVE: &str = "no-preserve-root";
+    }
+    pub mod dereference {
+        pub static DEREFERENCE: &str = "dereference";
+        pub static NO_DEREFERENCE: &str = "no-dereference";
+    }
+    pub static FROM: &str = "from";
+    pub static RECURSIVE: &str = "recursive";
+    pub mod traverse {
+        pub static TRAVERSE: &str = "H";
+        pub static NO_TRAVERSE: &str = "P";
+        pub static EVERY: &str = "L";
+    }
+    pub static REFERENCE: &str = "reference";
+}
+
+static ARG_OWNER: &str = "owner";
+static ARG_FILES: &str = "files";
+
+fn get_usage() -> String {
+    format!(
+        "{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
+        uucore::execution_phrase()
+    )
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = get_usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    /* First arg is the owner/group */
+    let owner = matches.value_of(ARG_OWNER).unwrap();
+
+    /* Then the list of files */
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let preserve_root = matches.is_present(options::preserve_root::PRESERVE);
+
+    let mut derefer = if matches.is_present(options::dereference::NO_DEREFERENCE) {
+        1
+    } else {
+        0
+    };
+
+    let mut bit_flag = if matches.is_present(options::traverse::TRAVERSE) {
+        FTS_COMFOLLOW | FTS_PHYSICAL
+    } else if matches.is_present(options::traverse::EVERY) {
+        FTS_LOGICAL
+    } else {
+        FTS_PHYSICAL
+    };
+
+    let recursive = matches.is_present(options::RECURSIVE);
+    if recursive {
+        if bit_flag == FTS_PHYSICAL {
+            if derefer == 1 {
+                return Err(USimpleError::new(1, "-R --dereference requires -H or -L"));
+            }
+            derefer = 0;
+        }
+    } else {
+        bit_flag = FTS_PHYSICAL;
+    }
+
+    let verbosity = if matches.is_present(options::verbosity::CHANGES) {
+        VerbosityLevel::Changes
+    } else if matches.is_present(options::verbosity::SILENT)
+        || matches.is_present(options::verbosity::QUIET)
+    {
+        VerbosityLevel::Silent
+    } else if matches.is_present(options::verbosity::VERBOSE) {
+        VerbosityLevel::Verbose
+    } else {
+        VerbosityLevel::Normal
+    };
+
+    let filter = if let Some(spec) = matches.value_of(options::FROM) {
+        match parse_spec(spec)? {
+            (Some(uid), None) => IfFrom::User(uid),
+            (None, Some(gid)) => IfFrom::Group(gid),
+            (Some(uid), Some(gid)) => IfFrom::UserGroup(uid, gid),
+            (None, None) => IfFrom::All,
+        }
+    } else {
+        IfFrom::All
+    };
+
+    let dest_uid: Option<u32>;
+    let dest_gid: Option<u32>;
+    if let Some(file) = matches.value_of(options::REFERENCE) {
+        let meta = fs::metadata(&file)
+            .map_err_context(|| format!("failed to get attributes of '{}'", file))?;
+        dest_gid = Some(meta.gid());
+        dest_uid = Some(meta.uid());
+    } else {
+        let (u, g) = parse_spec(owner)?;
+        dest_uid = u;
+        dest_gid = g;
+    }
+    let executor = ChownExecutor {
+        bit_flag,
+        dest_uid,
+        dest_gid,
+        verbosity: Verbosity {
+            groups_only: false,
+            level: verbosity,
+        },
+        recursive,
+        dereference: derefer != 0,
+        filter,
+        preserve_root,
+        files,
+    };
+    executor.exec()
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::verbosity::CHANGES)
+                .short("c")
+                .long(options::verbosity::CHANGES)
+                .help("like verbose but report only when a change is made"),
+        )
+        .arg(Arg::with_name(options::dereference::DEREFERENCE).long(options::dereference::DEREFERENCE).help(
+            "affect the referent of each symbolic link (this is the default), rather than the symbolic link itself",
+        ))
+        .arg(
+            Arg::with_name(options::dereference::NO_DEREFERENCE)
+                .short("h")
+                .long(options::dereference::NO_DEREFERENCE)
+                .help(
+                    "affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::FROM)
+                .long(options::FROM)
+                .help(
+                    "change the owner and/or group of each file only if its current owner and/or group match those specified here. Either may be omitted, in which case a match is not required for the omitted attribute",
+                )
+                .value_name("CURRENT_OWNER:CURRENT_GROUP"),
+        )
+        .arg(
+            Arg::with_name(options::preserve_root::PRESERVE)
+                .long(options::preserve_root::PRESERVE)
+                .help("fail to operate recursively on '/'"),
+        )
+        .arg(
+            Arg::with_name(options::preserve_root::NO_PRESERVE)
+                .long(options::preserve_root::NO_PRESERVE)
+                .help("do not treat '/' specially (the default)"),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::QUIET)
+                .long(options::verbosity::QUIET)
+                .help("suppress most error messages"),
+        )
+        .arg(
+            Arg::with_name(options::RECURSIVE)
+                .short("R")
+                .long(options::RECURSIVE)
+                .help("operate on files and directories recursively"),
+        )
+        .arg(
+            Arg::with_name(options::REFERENCE)
+                .long(options::REFERENCE)
+                .help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
+                .value_name("RFILE")
+                .min_values(1),
+        )
+        .arg(Arg::with_name(options::verbosity::SILENT).short("f").long(options::verbosity::SILENT))
+        .arg(
+            Arg::with_name(options::traverse::TRAVERSE)
+                .short(options::traverse::TRAVERSE)
+                .help("if a command line argument is a symbolic link to a directory, traverse it")
+                .overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
+        )
+        .arg(
+            Arg::with_name(options::traverse::EVERY)
+                .short(options::traverse::EVERY)
+                .help("traverse every symbolic link to a directory encountered")
+                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
+        )
+        .arg(
+            Arg::with_name(options::traverse::NO_TRAVERSE)
+                .short(options::traverse::NO_TRAVERSE)
+                .help("do not traverse any symbolic links (default)")
+                .overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::VERBOSE)
+                .long(options::verbosity::VERBOSE)
+                .help("output a diagnostic for every file processed"),
+        )
+        .arg(
+            Arg::with_name(ARG_OWNER)
+                .multiple(false)
+                .takes_value(true)
+                .required(true),
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .required(true)
+                .min_values(1),
+        )
+}
+
+fn parse_spec(spec: &str) -> UResult<(Option<u32>, Option<u32>)> {
+    let args = spec.split_terminator(':').collect::<Vec<_>>();
+    let usr_only = args.len() == 1 && !args[0].is_empty();
+    let grp_only = args.len() == 2 && args[0].is_empty();
+    let usr_grp = args.len() == 2 && !args[0].is_empty() && !args[1].is_empty();
+    let uid = if usr_only || usr_grp {
+        Some(
+            Passwd::locate(args[0])
+                .map_err(|_| USimpleError::new(1, format!("invalid user: '{}'", spec)))?
+                .uid(),
+        )
+    } else {
+        None
+    };
+    let gid = if grp_only || usr_grp {
+        Some(
+            Group::locate(args[1])
+                .map_err(|_| USimpleError::new(1, format!("invalid group: '{}'", spec)))?
+                .gid(),
+        )
+    } else {
+        None
+    };
+    Ok((uid, gid))
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_parse_spec() {
+        assert!(matches!(parse_spec(":"), Ok((None, None))));
+        assert!(format!("{}", parse_spec("::").err().unwrap()).starts_with("invalid group: "));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_chroot/chroot.rs.html b/src/uu_chroot/chroot.rs.html new file mode 100644 index 000000000..5b0fce5f7 --- /dev/null +++ b/src/uu_chroot/chroot.rs.html @@ -0,0 +1,485 @@ +chroot.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Vsevolod Velichko <torkvemada@sorokdva.net>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) NEWROOT Userspec pstatus
+
+#[macro_use]
+extern crate uucore;
+use clap::{crate_version, App, Arg};
+use std::ffi::CString;
+use std::io::Error;
+use std::path::Path;
+use std::process::Command;
+use uucore::libc::{self, chroot, setgid, setgroups, setuid};
+use uucore::{entries, InvalidEncodingHandling};
+
+static ABOUT: &str = "Run COMMAND with root directory set to NEWROOT.";
+static SYNTAX: &str = "[OPTION]... NEWROOT [COMMAND [ARG]...]";
+
+mod options {
+    pub const NEWROOT: &str = "newroot";
+    pub const USER: &str = "user";
+    pub const GROUP: &str = "group";
+    pub const GROUPS: &str = "groups";
+    pub const USERSPEC: &str = "userspec";
+    pub const COMMAND: &str = "command";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let default_shell: &'static str = "/bin/sh";
+    let default_option: &'static str = "-i";
+    let user_shell = std::env::var("SHELL");
+
+    let newroot: &Path = match matches.value_of(options::NEWROOT) {
+        Some(v) => Path::new(v),
+        None => crash!(
+            1,
+            "Missing operand: NEWROOT\nTry '{} --help' for more information.",
+            uucore::execution_phrase()
+        ),
+    };
+
+    if !newroot.is_dir() {
+        crash!(
+            1,
+            "cannot change root directory to `{}`: no such directory",
+            newroot.display()
+        );
+    }
+
+    let commands = match matches.values_of(options::COMMAND) {
+        Some(v) => v.collect(),
+        None => vec![],
+    };
+
+    // TODO: refactor the args and command matching
+    // See: https://github.com/uutils/coreutils/pull/2365#discussion_r647849967
+    let command: Vec<&str> = match commands.len() {
+        1 => {
+            let shell: &str = match user_shell {
+                Err(_) => default_shell,
+                Ok(ref s) => s.as_ref(),
+            };
+            vec![shell, default_option]
+        }
+        _ => commands,
+    };
+
+    set_context(newroot, &matches);
+
+    let pstatus = Command::new(command[0])
+        .args(&command[1..])
+        .status()
+        .unwrap_or_else(|e| crash!(1, "Cannot exec: {}", e));
+
+    if pstatus.success() {
+        0
+    } else {
+        pstatus.code().unwrap_or(-1)
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .usage(SYNTAX)
+        .arg(
+            Arg::with_name(options::NEWROOT)
+                .hidden(true)
+                .required(true)
+                .index(1),
+        )
+        .arg(
+            Arg::with_name(options::USER)
+                .short("u")
+                .long(options::USER)
+                .help("User (ID or name) to switch before running the program")
+                .value_name("USER"),
+        )
+        .arg(
+            Arg::with_name(options::GROUP)
+                .short("g")
+                .long(options::GROUP)
+                .help("Group (ID or name) to switch to")
+                .value_name("GROUP"),
+        )
+        .arg(
+            Arg::with_name(options::GROUPS)
+                .short("G")
+                .long(options::GROUPS)
+                .help("Comma-separated list of groups to switch to")
+                .value_name("GROUP1,GROUP2..."),
+        )
+        .arg(
+            Arg::with_name(options::USERSPEC)
+                .long(options::USERSPEC)
+                .help(
+                    "Colon-separated user and group to switch to. \
+                     Same as -u USER -g GROUP. \
+                     Userspec has higher preference than -u and/or -g",
+                )
+                .value_name("USER:GROUP"),
+        )
+        .arg(
+            Arg::with_name(options::COMMAND)
+                .hidden(true)
+                .multiple(true)
+                .index(2),
+        )
+}
+
+fn set_context(root: &Path, options: &clap::ArgMatches) {
+    let userspec_str = options.value_of(options::USERSPEC);
+    let user_str = options.value_of(options::USER).unwrap_or_default();
+    let group_str = options.value_of(options::GROUP).unwrap_or_default();
+    let groups_str = options.value_of(options::GROUPS).unwrap_or_default();
+    let userspec = match userspec_str {
+        Some(u) => {
+            let s: Vec<&str> = u.split(':').collect();
+            if s.len() != 2 || s.iter().any(|&spec| spec.is_empty()) {
+                crash!(1, "invalid userspec: `{}`", u)
+            };
+            s
+        }
+        None => Vec::new(),
+    };
+
+    let (user, group) = if userspec.is_empty() {
+        (user_str, group_str)
+    } else {
+        (userspec[0], userspec[1])
+    };
+
+    enter_chroot(root);
+
+    set_groups_from_str(groups_str);
+    set_main_group(group);
+    set_user(user);
+}
+
+fn enter_chroot(root: &Path) {
+    let root_str = root.display();
+    std::env::set_current_dir(root).unwrap();
+    let err = unsafe {
+        chroot(CString::new(".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char)
+    };
+    if err != 0 {
+        crash!(
+            1,
+            "cannot chroot to {}: {}",
+            root_str,
+            Error::last_os_error()
+        )
+    };
+}
+
+fn set_main_group(group: &str) {
+    if !group.is_empty() {
+        let group_id = match entries::grp2gid(group) {
+            Ok(g) => g,
+            _ => crash!(1, "no such group: {}", group),
+        };
+        let err = unsafe { setgid(group_id) };
+        if err != 0 {
+            crash!(
+                1,
+                "cannot set gid to {}: {}",
+                group_id,
+                Error::last_os_error()
+            )
+        }
+    }
+}
+
+#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
+fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
+    unsafe { setgroups(groups.len() as libc::c_int, groups.as_ptr()) }
+}
+
+#[cfg(target_os = "linux")]
+fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
+    unsafe { setgroups(groups.len() as libc::size_t, groups.as_ptr()) }
+}
+
+fn set_groups_from_str(groups: &str) {
+    if !groups.is_empty() {
+        let groups_vec: Vec<libc::gid_t> = groups
+            .split(',')
+            .map(|x| match entries::grp2gid(x) {
+                Ok(g) => g,
+                _ => crash!(1, "no such group: {}", x),
+            })
+            .collect();
+        let err = set_groups(groups_vec);
+        if err != 0 {
+            crash!(1, "cannot set groups: {}", Error::last_os_error())
+        }
+    }
+}
+
+fn set_user(user: &str) {
+    if !user.is_empty() {
+        let user_id = entries::usr2uid(user).unwrap();
+        let err = unsafe { setuid(user_id as libc::uid_t) };
+        if err != 0 {
+            crash!(1, "cannot set user to {}: {}", user, Error::last_os_error())
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_cksum/cksum.rs.html b/src/uu_cksum/cksum.rs.html new file mode 100644 index 000000000..dc979d8e6 --- /dev/null +++ b/src/uu_cksum/cksum.rs.html @@ -0,0 +1,449 @@ +cksum.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Michael Gehring <mg@ebfe.org>
+//
+//  For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) fname
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{self, stdin, BufReader, Read};
+use std::path::Path;
+use uucore::InvalidEncodingHandling;
+
+// NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8
+const CRC_TABLE_LEN: usize = 256;
+const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table();
+
+const NAME: &str = "cksum";
+const SYNTAX: &str = "[OPTIONS] [FILE]...";
+const SUMMARY: &str = "Print CRC and size for each file";
+
+// this is basically a hack to get "loops" to work on Rust 1.33.  Once we update to Rust 1.46 or
+// greater, we can just use while loops
+macro_rules! unroll {
+    (256, |$i:ident| $s:expr) => {{
+        unroll!(@ 32, 0 * 32, $i, $s);
+        unroll!(@ 32, 1 * 32, $i, $s);
+        unroll!(@ 32, 2 * 32, $i, $s);
+        unroll!(@ 32, 3 * 32, $i, $s);
+        unroll!(@ 32, 4 * 32, $i, $s);
+        unroll!(@ 32, 5 * 32, $i, $s);
+        unroll!(@ 32, 6 * 32, $i, $s);
+        unroll!(@ 32, 7 * 32, $i, $s);
+    }};
+    (8, |$i:ident| $s:expr) => {{
+        unroll!(@ 8, 0, $i, $s);
+    }};
+
+    (@ 32, $start:expr, $i:ident, $s:expr) => {{
+        unroll!(@ 8, $start + 0 * 8, $i, $s);
+        unroll!(@ 8, $start + 1 * 8, $i, $s);
+        unroll!(@ 8, $start + 2 * 8, $i, $s);
+        unroll!(@ 8, $start + 3 * 8, $i, $s);
+    }};
+    (@ 8, $start:expr, $i:ident, $s:expr) => {{
+        unroll!(@ 4, $start, $i, $s);
+        unroll!(@ 4, $start + 4, $i, $s);
+    }};
+    (@ 4, $start:expr, $i:ident, $s:expr) => {{
+        unroll!(@ 2, $start, $i, $s);
+        unroll!(@ 2, $start + 2, $i, $s);
+    }};
+    (@ 2, $start:expr, $i:ident, $s:expr) => {{
+        unroll!(@ 1, $start, $i, $s);
+        unroll!(@ 1, $start + 1, $i, $s);
+    }};
+    (@ 1, $start:expr, $i:ident, $s:expr) => {{
+        let $i = $start;
+        let _ = $s;
+    }};
+}
+
+const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
+    let mut table = [0; CRC_TABLE_LEN];
+
+    // NOTE: works on Rust 1.46
+    //let mut i = 0;
+    //while i < CRC_TABLE_LEN {
+    //    table[i] = crc_entry(i as u8) as u32;
+    //
+    //    i += 1;
+    //}
+    unroll!(256, |i| {
+        table[i] = crc_entry(i as u8) as u32;
+    });
+
+    table
+}
+
+const fn crc_entry(input: u8) -> u32 {
+    let mut crc = (input as u32) << 24;
+
+    // NOTE: this does not work on Rust 1.33, but *does* on 1.46
+    //let mut i = 0;
+    //while i < 8 {
+    //    if crc & 0x8000_0000 != 0 {
+    //        crc <<= 1;
+    //        crc ^= 0x04c1_1db7;
+    //    } else {
+    //        crc <<= 1;
+    //    }
+    //
+    //    i += 1;
+    //}
+    unroll!(8, |_i| {
+        let if_condition = crc & 0x8000_0000;
+        let if_body = (crc << 1) ^ 0x04c1_1db7;
+        let else_body = crc << 1;
+
+        // NOTE: i feel like this is easier to understand than emulating an if statement in bitwise
+        //       ops
+        let condition_table = [else_body, if_body];
+
+        crc = condition_table[(if_condition != 0) as usize];
+    });
+
+    crc
+}
+
+#[inline]
+fn crc_update(crc: u32, input: u8) -> u32 {
+    (crc << 8) ^ CRC_TABLE[((crc >> 24) as usize ^ input as usize) & 0xFF]
+}
+
+#[inline]
+fn crc_final(mut crc: u32, mut length: usize) -> u32 {
+    while length != 0 {
+        crc = crc_update(crc, length as u8);
+        length >>= 8;
+    }
+
+    !crc
+}
+
+fn init_byte_array() -> Vec<u8> {
+    vec![0; 1024 * 1024]
+}
+
+#[inline]
+fn cksum(fname: &str) -> io::Result<(u32, usize)> {
+    let mut crc = 0u32;
+    let mut size = 0usize;
+
+    let file;
+    let mut rd: Box<dyn Read> = match fname {
+        "-" => Box::new(stdin()),
+        _ => {
+            let path = &Path::new(fname);
+            if path.is_dir() {
+                return Err(std::io::Error::new(
+                    io::ErrorKind::InvalidInput,
+                    "Is a directory",
+                ));
+            };
+            if path.metadata().is_err() {
+                return Err(std::io::Error::new(
+                    io::ErrorKind::NotFound,
+                    "No such file or directory",
+                ));
+            };
+            file = File::open(&path)?;
+            Box::new(BufReader::new(file))
+        }
+    };
+
+    let mut bytes = init_byte_array();
+    loop {
+        let num_bytes = rd.read(&mut bytes)?;
+        if num_bytes == 0 {
+            return Ok((crc_final(crc, size), size));
+        }
+        for &b in bytes[..num_bytes].iter() {
+            crc = crc_update(crc, b);
+        }
+        size += num_bytes;
+    }
+}
+
+mod options {
+    pub static FILE: &str = "file";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let files: Vec<String> = match matches.values_of(options::FILE) {
+        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
+        None => vec![],
+    };
+
+    if files.is_empty() {
+        match cksum("-") {
+            Ok((crc, size)) => println!("{} {}", crc, size),
+            Err(err) => {
+                show_error!("{}", err);
+                return 2;
+            }
+        }
+        return 0;
+    }
+
+    let mut exit_code = 0;
+    for fname in &files {
+        match cksum(fname.as_ref()) {
+            Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
+            Err(err) => {
+                show_error!("'{}' {}", fname, err);
+                exit_code = 2;
+            }
+        }
+    }
+
+    exit_code
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .about(SUMMARY)
+        .usage(SYNTAX)
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_comm/comm.rs.html b/src/uu_comm/comm.rs.html new file mode 100644 index 000000000..3dde2a3eb --- /dev/null +++ b/src/uu_comm/comm.rs.html @@ -0,0 +1,359 @@ +comm.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Michael Gehring <mg@ebfe.org>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) delim mkdelim
+
+use std::cmp::Ordering;
+use std::fs::File;
+use std::io::{self, stdin, BufRead, BufReader, Stdin};
+use std::path::Path;
+use uucore::InvalidEncodingHandling;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+
+static ABOUT: &str = "compare two sorted files line by line";
+static LONG_HELP: &str = "";
+
+mod options {
+    pub const COLUMN_1: &str = "1";
+    pub const COLUMN_2: &str = "2";
+    pub const COLUMN_3: &str = "3";
+    pub const DELIMITER: &str = "output-delimiter";
+    pub const DELIMITER_DEFAULT: &str = "\t";
+    pub const FILE_1: &str = "FILE1";
+    pub const FILE_2: &str = "FILE2";
+}
+
+fn usage() -> String {
+    format!("{} [OPTION]... FILE1 FILE2", uucore::execution_phrase())
+}
+
+fn mkdelim(col: usize, opts: &ArgMatches) -> String {
+    let mut s = String::new();
+    let delim = opts.value_of(options::DELIMITER).unwrap();
+
+    if col > 1 && !opts.is_present(options::COLUMN_1) {
+        s.push_str(delim.as_ref());
+    }
+    if col > 2 && !opts.is_present(options::COLUMN_2) {
+        s.push_str(delim.as_ref());
+    }
+
+    s
+}
+
+fn ensure_nl(line: &mut String) {
+    if !line.ends_with('\n') {
+        line.push('\n');
+    }
+}
+
+enum LineReader {
+    Stdin(Stdin),
+    FileIn(BufReader<File>),
+}
+
+impl LineReader {
+    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
+        match *self {
+            LineReader::Stdin(ref mut r) => r.read_line(buf),
+            LineReader::FileIn(ref mut r) => r.read_line(buf),
+        }
+    }
+}
+
+fn comm(a: &mut LineReader, b: &mut LineReader, opts: &ArgMatches) {
+    let delim: Vec<String> = (0..4).map(|col| mkdelim(col, opts)).collect();
+
+    let ra = &mut String::new();
+    let mut na = a.read_line(ra);
+    let rb = &mut String::new();
+    let mut nb = b.read_line(rb);
+
+    while na.is_ok() || nb.is_ok() {
+        let ord = match (na.is_ok(), nb.is_ok()) {
+            (false, true) => Ordering::Greater,
+            (true, false) => Ordering::Less,
+            (true, true) => match (&na, &nb) {
+                (&Ok(0), &Ok(0)) => break,
+                (&Ok(0), _) => Ordering::Greater,
+                (_, &Ok(0)) => Ordering::Less,
+                _ => ra.cmp(&rb),
+            },
+            _ => unreachable!(),
+        };
+
+        match ord {
+            Ordering::Less => {
+                if !opts.is_present(options::COLUMN_1) {
+                    ensure_nl(ra);
+                    print!("{}{}", delim[1], ra);
+                }
+                ra.clear();
+                na = a.read_line(ra);
+            }
+            Ordering::Greater => {
+                if !opts.is_present(options::COLUMN_2) {
+                    ensure_nl(rb);
+                    print!("{}{}", delim[2], rb);
+                }
+                rb.clear();
+                nb = b.read_line(rb);
+            }
+            Ordering::Equal => {
+                if !opts.is_present(options::COLUMN_3) {
+                    ensure_nl(ra);
+                    print!("{}{}", delim[3], ra);
+                }
+                ra.clear();
+                rb.clear();
+                na = a.read_line(ra);
+                nb = b.read_line(rb);
+            }
+        }
+    }
+}
+
+fn open_file(name: &str) -> io::Result<LineReader> {
+    match name {
+        "-" => Ok(LineReader::Stdin(stdin())),
+        _ => {
+            let f = File::open(&Path::new(name))?;
+            Ok(LineReader::FileIn(BufReader::new(f)))
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mut f1 = open_file(matches.value_of(options::FILE_1).unwrap()).unwrap();
+    let mut f2 = open_file(matches.value_of(options::FILE_2).unwrap()).unwrap();
+
+    comm(&mut f1, &mut f2, &matches);
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::COLUMN_1)
+                .short(options::COLUMN_1)
+                .help("suppress column 1 (lines unique to FILE1)"),
+        )
+        .arg(
+            Arg::with_name(options::COLUMN_2)
+                .short(options::COLUMN_2)
+                .help("suppress column 2 (lines unique to FILE2)"),
+        )
+        .arg(
+            Arg::with_name(options::COLUMN_3)
+                .short(options::COLUMN_3)
+                .help("suppress column 3 (lines that appear in both files)"),
+        )
+        .arg(
+            Arg::with_name(options::DELIMITER)
+                .long(options::DELIMITER)
+                .help("separate columns with STR")
+                .value_name("STR")
+                .default_value(options::DELIMITER_DEFAULT)
+                .hide_default_value(true),
+        )
+        .arg(Arg::with_name(options::FILE_1).required(true))
+        .arg(Arg::with_name(options::FILE_2).required(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_cp/cp.rs.html b/src/uu_cp/cp.rs.html new file mode 100644 index 000000000..9d4a6a8ec --- /dev/null +++ b/src/uu_cp/cp.rs.html @@ -0,0 +1,2905 @@ +cp.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+
+#![allow(clippy::missing_safety_doc)]
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jordy Dickinson <jordy.dickinson@gmail.com>
+// (c) Joshua S. Miller <jsmiller@uchicago.edu>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) ficlone linkgs lstat nlink nlinks pathbuf reflink strs xattrs
+
+#[cfg(target_os = "linux")]
+#[macro_use]
+extern crate ioctl_sys;
+#[macro_use]
+extern crate quick_error;
+#[macro_use]
+extern crate uucore;
+
+#[cfg(windows)]
+use winapi::um::fileapi::CreateFileW;
+#[cfg(windows)]
+use winapi::um::fileapi::GetFileInformationByHandle;
+
+use std::borrow::Cow;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use filetime::FileTime;
+use quick_error::ResultExt;
+use std::collections::HashSet;
+use std::env;
+#[cfg(not(windows))]
+use std::ffi::CString;
+#[cfg(windows)]
+use std::ffi::OsStr;
+use std::fs;
+use std::fs::File;
+use std::fs::OpenOptions;
+use std::io;
+use std::io::{stdin, stdout, Write};
+use std::mem;
+#[cfg(target_os = "linux")]
+use std::os::unix::io::AsRawFd;
+#[cfg(windows)]
+use std::os::windows::ffi::OsStrExt;
+use std::path::{Path, PathBuf, StripPrefixError};
+use std::str::FromStr;
+use std::string::ToString;
+use uucore::backup_control::{self, BackupMode};
+use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
+use walkdir::WalkDir;
+
+#[cfg(unix)]
+use std::os::unix::fs::PermissionsExt;
+
+#[cfg(target_os = "linux")]
+ioctl!(write ficlone with 0x94, 9; std::os::raw::c_int);
+
+quick_error! {
+    #[derive(Debug)]
+    pub enum Error {
+        /// Simple io::Error wrapper
+        IoErr(err: io::Error) { from() cause(err) display("{}", err) }
+
+        /// Wrapper for io::Error with path context
+        IoErrContext(err: io::Error, path: String) {
+            display("{}: {}", path, err)
+            context(path: &'a str, err: io::Error) -> (err, path.to_owned())
+            cause(err)
+        }
+
+        /// General copy error
+        Error(err: String) {
+            display("{}", err)
+            from(err: String) -> (err)
+            from(err: &'static str) -> (err.to_string())
+        }
+
+        /// Represents the state when a non-fatal error has occurred
+        /// and not all files were copied.
+        NotAllFilesCopied {}
+
+        /// Simple walkdir::Error wrapper
+        WalkDirErr(err: walkdir::Error) { from() display("{}", err) cause(err) }
+
+        /// Simple std::path::StripPrefixError wrapper
+        StripPrefixError(err: StripPrefixError) { from() }
+
+        /// Result of a skipped file
+        Skipped(reason: String) { display("{}", reason) }
+
+        /// Result of a skipped file
+        InvalidArgument(description: String) { display("{}", description) }
+
+        /// All standard options are included as an an implementation
+        /// path, but those that are not implemented yet should return
+        /// a NotImplemented error.
+        NotImplemented(opt: String) { display("Option '{}' not yet implemented.", opt) }
+
+        /// Invalid arguments to backup
+        Backup(description: String) { display("{}\nTry '{} --help' for more information.", description, uucore::execution_phrase()) }
+    }
+}
+
+/// Continue next iteration of loop if result of expression is error
+macro_rules! or_continue(
+    ($expr:expr) => (match $expr {
+        Ok(temp) => temp,
+        Err(error) => {
+            show_error!("{}", error);
+            continue
+        },
+    })
+);
+
+/// Prompts the user yes/no and returns `true` if they successfully
+/// answered yes.
+macro_rules! prompt_yes(
+    ($($args:tt)+) => ({
+        print!($($args)+);
+        print!(" [y/N]: ");
+        crash_if_err!(1, stdout().flush());
+        let mut s = String::new();
+        match stdin().read_line(&mut s) {
+            Ok(_) => match s.char_indices().next() {
+                Some((_, x)) => x == 'y' || x == 'Y',
+                _ => false
+            },
+            _ => false
+        }
+    })
+);
+
+pub type CopyResult<T> = Result<T, Error>;
+pub type Source = PathBuf;
+pub type SourceSlice = Path;
+pub type Target = PathBuf;
+pub type TargetSlice = Path;
+
+/// Specifies whether when overwrite files
+#[derive(Clone, Eq, PartialEq)]
+pub enum ClobberMode {
+    Force,
+    RemoveDestination,
+    Standard,
+}
+
+/// Specifies whether when overwrite files
+#[derive(Clone, Eq, PartialEq)]
+pub enum OverwriteMode {
+    /// [Default] Always overwrite existing files
+    Clobber(ClobberMode),
+    /// Prompt before overwriting a file
+    Interactive(ClobberMode),
+    /// Never overwrite a file
+    NoClobber,
+}
+
+/// Possible arguments for `--reflink`.
+#[derive(Copy, Clone, Eq, PartialEq)]
+pub enum ReflinkMode {
+    Always,
+    Auto,
+    Never,
+}
+
+/// Specifies the expected file type of copy target
+pub enum TargetType {
+    Directory,
+    File,
+}
+
+pub enum CopyMode {
+    Link,
+    SymLink,
+    Sparse,
+    Copy,
+    Update,
+    AttrOnly,
+}
+
+#[derive(Clone, Eq, PartialEq)]
+pub enum Attribute {
+    #[cfg(unix)]
+    Mode,
+    Ownership,
+    Timestamps,
+    Context,
+    Links,
+    Xattr,
+}
+
+/// Re-usable, extensible copy options
+#[allow(dead_code)]
+pub struct Options {
+    attributes_only: bool,
+    backup: BackupMode,
+    copy_contents: bool,
+    copy_mode: CopyMode,
+    dereference: bool,
+    no_target_dir: bool,
+    one_file_system: bool,
+    overwrite: OverwriteMode,
+    parents: bool,
+    strip_trailing_slashes: bool,
+    reflink_mode: ReflinkMode,
+    preserve_attributes: Vec<Attribute>,
+    recursive: bool,
+    backup_suffix: String,
+    target_dir: Option<String>,
+    update: bool,
+    verbose: bool,
+}
+
+static ABOUT: &str = "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.";
+static LONG_HELP: &str = "";
+static EXIT_OK: i32 = 0;
+static EXIT_ERR: i32 = 1;
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [-T] SOURCE DEST
+    {0} [OPTION]... SOURCE... DIRECTORY
+    {0} [OPTION]... -t DIRECTORY SOURCE...",
+        uucore::execution_phrase()
+    )
+}
+
+// Argument constants
+mod options {
+    pub const ARCHIVE: &str = "archive";
+    pub const ATTRIBUTES_ONLY: &str = "attributes-only";
+    pub const BACKUP: &str = "backup";
+    pub const BACKUP_NO_ARG: &str = "b";
+    pub const CLI_SYMBOLIC_LINKS: &str = "cli-symbolic-links";
+    pub const CONTEXT: &str = "context";
+    pub const COPY_CONTENTS: &str = "copy-contents";
+    pub const DEREFERENCE: &str = "dereference";
+    pub const FORCE: &str = "force";
+    pub const INTERACTIVE: &str = "interactive";
+    pub const LINK: &str = "link";
+    pub const NO_CLOBBER: &str = "no-clobber";
+    pub const NO_DEREFERENCE: &str = "no-dereference";
+    pub const NO_DEREFERENCE_PRESERVE_LINKS: &str = "no-dereference-preserve-linkgs";
+    pub const NO_PRESERVE: &str = "no-preserve";
+    pub const NO_TARGET_DIRECTORY: &str = "no-target-directory";
+    pub const ONE_FILE_SYSTEM: &str = "one-file-system";
+    pub const PARENT: &str = "parent";
+    pub const PARENTS: &str = "parents";
+    pub const PATHS: &str = "paths";
+    pub const PRESERVE: &str = "preserve";
+    pub const PRESERVE_DEFAULT_ATTRIBUTES: &str = "preserve-default-attributes";
+    pub const RECURSIVE: &str = "recursive";
+    pub const RECURSIVE_ALIAS: &str = "recursive_alias";
+    pub const REFLINK: &str = "reflink";
+    pub const REMOVE_DESTINATION: &str = "remove-destination";
+    pub const SPARSE: &str = "sparse";
+    pub const STRIP_TRAILING_SLASHES: &str = "strip-trailing-slashes";
+    pub const SUFFIX: &str = "suffix";
+    pub const SYMBOLIC_LINK: &str = "symbolic-link";
+    pub const TARGET_DIRECTORY: &str = "target-directory";
+    pub const UPDATE: &str = "update";
+    pub const VERBOSE: &str = "verbose";
+}
+
+#[cfg(unix)]
+static PRESERVABLE_ATTRIBUTES: &[&str] = &[
+    "mode",
+    "ownership",
+    "timestamps",
+    "context",
+    "links",
+    "xattr",
+    "all",
+];
+
+#[cfg(not(unix))]
+static PRESERVABLE_ATTRIBUTES: &[&str] = &[
+    "ownership",
+    "timestamps",
+    "context",
+    "links",
+    "xattr",
+    "all",
+];
+
+static DEFAULT_ATTRIBUTES: &[Attribute] = &[
+    #[cfg(unix)]
+    Attribute::Mode,
+    Attribute::Ownership,
+    Attribute::Timestamps,
+];
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(Arg::with_name(options::TARGET_DIRECTORY)
+             .short("t")
+             .conflicts_with(options::NO_TARGET_DIRECTORY)
+             .long(options::TARGET_DIRECTORY)
+             .value_name(options::TARGET_DIRECTORY)
+             .takes_value(true)
+             .help("copy all SOURCE arguments into target-directory"))
+        .arg(Arg::with_name(options::NO_TARGET_DIRECTORY)
+             .short("T")
+             .long(options::NO_TARGET_DIRECTORY)
+             .conflicts_with(options::TARGET_DIRECTORY)
+             .help("Treat DEST as a regular file and not a directory"))
+        .arg(Arg::with_name(options::INTERACTIVE)
+             .short("i")
+             .long(options::INTERACTIVE)
+             .conflicts_with(options::NO_CLOBBER)
+             .help("ask before overwriting files"))
+        .arg(Arg::with_name(options::LINK)
+             .short("l")
+             .long(options::LINK)
+             .overrides_with(options::REFLINK)
+             .help("hard-link files instead of copying"))
+        .arg(Arg::with_name(options::NO_CLOBBER)
+             .short("n")
+             .long(options::NO_CLOBBER)
+             .conflicts_with(options::INTERACTIVE)
+             .help("don't overwrite a file that already exists"))
+        .arg(Arg::with_name(options::RECURSIVE)
+             .short("r")
+             .long(options::RECURSIVE)
+             // --archive sets this option
+            .help("copy directories recursively"))
+        .arg(Arg::with_name(options::RECURSIVE_ALIAS)
+             .short("R")
+             .help("same as -r"))
+        .arg(Arg::with_name(options::STRIP_TRAILING_SLASHES)
+             .long(options::STRIP_TRAILING_SLASHES)
+             .help("remove any trailing slashes from each SOURCE argument"))
+        .arg(Arg::with_name(options::VERBOSE)
+             .short("v")
+             .long(options::VERBOSE)
+             .help("explicitly state what is being done"))
+        .arg(Arg::with_name(options::SYMBOLIC_LINK)
+             .short("s")
+             .long(options::SYMBOLIC_LINK)
+             .conflicts_with(options::LINK)
+             .overrides_with(options::REFLINK)
+             .help("make symbolic links instead of copying"))
+        .arg(Arg::with_name(options::FORCE)
+             .short("f")
+             .long(options::FORCE)
+             .help("if an existing destination file cannot be opened, remove it and \
+                    try again (this option is ignored when the -n option is also used). \
+                    Currently not implemented for Windows."))
+        .arg(Arg::with_name(options::REMOVE_DESTINATION)
+             .long(options::REMOVE_DESTINATION)
+             .conflicts_with(options::FORCE)
+             .help("remove each existing destination file before attempting to open it \
+                    (contrast with --force). On Windows, current only works for writeable files."))
+        .arg(Arg::with_name(options::BACKUP)
+             .long(options::BACKUP)
+             .help("make a backup of each existing destination file")
+             .takes_value(true)
+             .require_equals(true)
+             .min_values(0)
+             .value_name("CONTROL")
+        )
+        .arg(Arg::with_name(options::BACKUP_NO_ARG)
+             .short(options::BACKUP_NO_ARG)
+             .help("like --backup but does not accept an argument")
+        )
+        .arg(Arg::with_name(options::SUFFIX)
+             .short("S")
+             .long(options::SUFFIX)
+             .takes_value(true)
+             .value_name("SUFFIX")
+             .help("override the usual backup suffix"))
+        .arg(Arg::with_name(options::UPDATE)
+             .short("u")
+             .long(options::UPDATE)
+             .help("copy only when the SOURCE file is newer than the destination file \
+                    or when the destination file is missing"))
+        .arg(Arg::with_name(options::REFLINK)
+             .long(options::REFLINK)
+             .takes_value(true)
+             .value_name("WHEN")
+             .help("control clone/CoW copies. See below"))
+        .arg(Arg::with_name(options::ATTRIBUTES_ONLY)
+             .long(options::ATTRIBUTES_ONLY)
+             .conflicts_with(options::COPY_CONTENTS)
+             .overrides_with(options::REFLINK)
+             .help("Don't copy the file data, just the attributes"))
+        .arg(Arg::with_name(options::PRESERVE)
+             .long(options::PRESERVE)
+             .takes_value(true)
+             .multiple(true)
+             .use_delimiter(true)
+             .possible_values(PRESERVABLE_ATTRIBUTES)
+             .min_values(0)
+             .value_name("ATTR_LIST")
+             .conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::NO_PRESERVE])
+             // -d sets this option
+             // --archive sets this option
+             .help("Preserve the specified attributes (default: mode (unix only), ownership, timestamps), \
+                    if possible additional attributes: context, links, xattr, all"))
+        .arg(Arg::with_name(options::PRESERVE_DEFAULT_ATTRIBUTES)
+             .short("-p")
+             .long(options::PRESERVE_DEFAULT_ATTRIBUTES)
+             .conflicts_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE])
+             .help("same as --preserve=mode(unix only),ownership,timestamps"))
+        .arg(Arg::with_name(options::NO_PRESERVE)
+             .long(options::NO_PRESERVE)
+             .takes_value(true)
+             .value_name("ATTR_LIST")
+             .conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::ARCHIVE])
+             .help("don't preserve the specified attributes"))
+        .arg(Arg::with_name(options::PARENTS)
+            .long(options::PARENTS)
+            .alias(options::PARENT)
+            .help("use full source file name under DIRECTORY"))
+        .arg(Arg::with_name(options::NO_DEREFERENCE)
+             .short("-P")
+             .long(options::NO_DEREFERENCE)
+             .conflicts_with(options::DEREFERENCE)
+             // -d sets this option
+             .help("never follow symbolic links in SOURCE"))
+        .arg(Arg::with_name(options::DEREFERENCE)
+             .short("L")
+             .long(options::DEREFERENCE)
+             .conflicts_with(options::NO_DEREFERENCE)
+             .help("always follow symbolic links in SOURCE"))
+        .arg(Arg::with_name(options::ARCHIVE)
+             .short("a")
+             .long(options::ARCHIVE)
+             .conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::NO_PRESERVE])
+             .help("Same as -dR --preserve=all"))
+        .arg(Arg::with_name(options::NO_DEREFERENCE_PRESERVE_LINKS)
+             .short("d")
+             .help("same as --no-dereference --preserve=links"))
+        .arg(Arg::with_name(options::ONE_FILE_SYSTEM)
+             .short("x")
+             .long(options::ONE_FILE_SYSTEM)
+             .help("stay on this file system"))
+
+        // TODO: implement the following args
+        .arg(Arg::with_name(options::COPY_CONTENTS)
+             .long(options::COPY_CONTENTS)
+             .conflicts_with(options::ATTRIBUTES_ONLY)
+             .help("NotImplemented: copy contents of special files when recursive"))
+        .arg(Arg::with_name(options::SPARSE)
+             .long(options::SPARSE)
+             .takes_value(true)
+             .value_name("WHEN")
+             .help("NotImplemented: control creation of sparse files. See below"))
+        .arg(Arg::with_name(options::CONTEXT)
+             .long(options::CONTEXT)
+             .takes_value(true)
+             .value_name("CTX")
+             .help("NotImplemented: set SELinux security context of destination file to default type"))
+        .arg(Arg::with_name(options::CLI_SYMBOLIC_LINKS)
+             .short("H")
+             .help("NotImplemented: follow command-line symbolic links in SOURCE"))
+        // END TODO
+
+        .arg(Arg::with_name(options::PATHS)
+             .multiple(true))
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app()
+        .after_help(&*format!(
+            "{}\n{}",
+            LONG_HELP,
+            backup_control::BACKUP_CONTROL_LONG_HELP
+        ))
+        .usage(&usage[..])
+        .get_matches_from(args);
+
+    let options = crash_if_err!(EXIT_ERR, Options::from_matches(&matches));
+
+    if options.overwrite == OverwriteMode::NoClobber && options.backup != BackupMode::NoBackup {
+        show_usage_error!("options --backup and --no-clobber are mutually exclusive");
+        return 1;
+    }
+
+    let paths: Vec<String> = matches
+        .values_of(options::PATHS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let (sources, target) = crash_if_err!(EXIT_ERR, parse_path_args(&paths, &options));
+
+    if let Err(error) = copy(&sources, &target, &options) {
+        match error {
+            // Error::NotAllFilesCopied is non-fatal, but the error
+            // code should still be EXIT_ERR as does GNU cp
+            Error::NotAllFilesCopied => {}
+            // Else we caught a fatal bubbled-up error, log it to stderr
+            _ => show_error!("{}", error),
+        };
+        return EXIT_ERR;
+    }
+
+    EXIT_OK
+}
+
+impl ClobberMode {
+    fn from_matches(matches: &ArgMatches) -> ClobberMode {
+        if matches.is_present(options::FORCE) {
+            ClobberMode::Force
+        } else if matches.is_present(options::REMOVE_DESTINATION) {
+            ClobberMode::RemoveDestination
+        } else {
+            ClobberMode::Standard
+        }
+    }
+}
+
+impl OverwriteMode {
+    fn from_matches(matches: &ArgMatches) -> OverwriteMode {
+        if matches.is_present(options::INTERACTIVE) {
+            OverwriteMode::Interactive(ClobberMode::from_matches(matches))
+        } else if matches.is_present(options::NO_CLOBBER) {
+            OverwriteMode::NoClobber
+        } else {
+            OverwriteMode::Clobber(ClobberMode::from_matches(matches))
+        }
+    }
+}
+
+impl CopyMode {
+    fn from_matches(matches: &ArgMatches) -> CopyMode {
+        if matches.is_present(options::LINK) {
+            CopyMode::Link
+        } else if matches.is_present(options::SYMBOLIC_LINK) {
+            CopyMode::SymLink
+        } else if matches.is_present(options::SPARSE) {
+            CopyMode::Sparse
+        } else if matches.is_present(options::UPDATE) {
+            CopyMode::Update
+        } else if matches.is_present(options::ATTRIBUTES_ONLY) {
+            CopyMode::AttrOnly
+        } else {
+            CopyMode::Copy
+        }
+    }
+}
+
+impl FromStr for Attribute {
+    type Err = Error;
+
+    fn from_str(value: &str) -> CopyResult<Attribute> {
+        Ok(match &*value.to_lowercase() {
+            #[cfg(unix)]
+            "mode" => Attribute::Mode,
+            "ownership" => Attribute::Ownership,
+            "timestamps" => Attribute::Timestamps,
+            "context" => Attribute::Context,
+            "links" => Attribute::Links,
+            "xattr" => Attribute::Xattr,
+            _ => {
+                return Err(Error::InvalidArgument(format!(
+                    "invalid attribute '{}'",
+                    value
+                )));
+            }
+        })
+    }
+}
+
+fn add_all_attributes() -> Vec<Attribute> {
+    use Attribute::*;
+
+    #[cfg(target_os = "windows")]
+    let attr = vec![Ownership, Timestamps, Context, Xattr, Links];
+
+    #[cfg(not(target_os = "windows"))]
+    let mut attr = vec![Ownership, Timestamps, Context, Xattr, Links];
+
+    #[cfg(unix)]
+    attr.insert(0, Mode);
+
+    attr
+}
+
+impl Options {
+    fn from_matches(matches: &ArgMatches) -> CopyResult<Options> {
+        let not_implemented_opts = vec![
+            options::COPY_CONTENTS,
+            options::SPARSE,
+            #[cfg(not(any(windows, unix)))]
+            options::ONE_FILE_SYSTEM,
+            options::CONTEXT,
+            #[cfg(windows)]
+            options::FORCE,
+        ];
+
+        for not_implemented_opt in not_implemented_opts {
+            if matches.is_present(not_implemented_opt) {
+                return Err(Error::NotImplemented(not_implemented_opt.to_string()));
+            }
+        }
+
+        let recursive = matches.is_present(options::RECURSIVE)
+            || matches.is_present(options::RECURSIVE_ALIAS)
+            || matches.is_present(options::ARCHIVE);
+
+        let backup_mode = backup_control::determine_backup_mode(
+            matches.is_present(options::BACKUP_NO_ARG),
+            matches.is_present(options::BACKUP),
+            matches.value_of(options::BACKUP),
+        );
+        let backup_mode = match backup_mode {
+            Err(err) => {
+                return Err(Error::Backup(err));
+            }
+            Ok(mode) => mode,
+        };
+
+        let backup_suffix =
+            backup_control::determine_backup_suffix(matches.value_of(options::SUFFIX));
+
+        let overwrite = OverwriteMode::from_matches(matches);
+
+        // Parse target directory options
+        let no_target_dir = matches.is_present(options::NO_TARGET_DIRECTORY);
+        let target_dir = matches
+            .value_of(options::TARGET_DIRECTORY)
+            .map(ToString::to_string);
+
+        // Parse attributes to preserve
+        let preserve_attributes: Vec<Attribute> = if matches.is_present(options::PRESERVE) {
+            match matches.values_of(options::PRESERVE) {
+                None => DEFAULT_ATTRIBUTES.to_vec(),
+                Some(attribute_strs) => {
+                    let mut attributes = Vec::new();
+                    for attribute_str in attribute_strs {
+                        if attribute_str == "all" {
+                            attributes = add_all_attributes();
+                            break;
+                        } else {
+                            attributes.push(Attribute::from_str(attribute_str)?);
+                        }
+                    }
+                    attributes
+                }
+            }
+        } else if matches.is_present(options::ARCHIVE) {
+            // --archive is used. Same as --preserve=all
+            add_all_attributes()
+        } else if matches.is_present(options::NO_DEREFERENCE_PRESERVE_LINKS) {
+            vec![Attribute::Links]
+        } else if matches.is_present(options::PRESERVE_DEFAULT_ATTRIBUTES) {
+            DEFAULT_ATTRIBUTES.to_vec()
+        } else {
+            vec![]
+        };
+
+        let options = Options {
+            attributes_only: matches.is_present(options::ATTRIBUTES_ONLY),
+            copy_contents: matches.is_present(options::COPY_CONTENTS),
+            copy_mode: CopyMode::from_matches(matches),
+            // No dereference is set with -p, -d and --archive
+            dereference: !(matches.is_present(options::NO_DEREFERENCE)
+                || matches.is_present(options::NO_DEREFERENCE_PRESERVE_LINKS)
+                || matches.is_present(options::ARCHIVE)
+                || recursive)
+                || matches.is_present(options::DEREFERENCE),
+            one_file_system: matches.is_present(options::ONE_FILE_SYSTEM),
+            parents: matches.is_present(options::PARENTS),
+            update: matches.is_present(options::UPDATE),
+            verbose: matches.is_present(options::VERBOSE),
+            strip_trailing_slashes: matches.is_present(options::STRIP_TRAILING_SLASHES),
+            reflink_mode: {
+                if let Some(reflink) = matches.value_of(options::REFLINK) {
+                    match reflink {
+                        "always" => ReflinkMode::Always,
+                        "auto" => ReflinkMode::Auto,
+                        "never" => ReflinkMode::Never,
+                        value => {
+                            return Err(Error::InvalidArgument(format!(
+                                "invalid argument '{}' for \'reflink\'",
+                                value
+                            )));
+                        }
+                    }
+                } else {
+                    #[cfg(any(target_os = "linux", target_os = "macos"))]
+                    {
+                        ReflinkMode::Auto
+                    }
+                    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+                    {
+                        ReflinkMode::Never
+                    }
+                }
+            },
+            backup: backup_mode,
+            backup_suffix,
+            overwrite,
+            no_target_dir,
+            preserve_attributes,
+            recursive,
+            target_dir,
+        };
+
+        Ok(options)
+    }
+}
+
+impl TargetType {
+    /// Return TargetType required for `target`.
+    ///
+    /// Treat target as a dir if we have multiple sources or the target
+    /// exists and already is a directory
+    fn determine(sources: &[Source], target: &TargetSlice) -> TargetType {
+        if sources.len() > 1 || target.is_dir() {
+            TargetType::Directory
+        } else {
+            TargetType::File
+        }
+    }
+}
+
+/// Returns tuple of (Source paths, Target)
+fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<Source>, Target)> {
+    let mut paths = path_args.iter().map(PathBuf::from).collect::<Vec<_>>();
+
+    if paths.is_empty() {
+        // No files specified
+        return Err("missing file operand".into());
+    }
+
+    // Return an error if the user requested to copy more than one
+    // file source to a file target
+    if options.no_target_dir && options.target_dir.is_none() && paths.len() > 2 {
+        return Err(format!("extra operand {:?}", paths[2]).into());
+    }
+
+    let target = match options.target_dir {
+        Some(ref target) => {
+            // All path args are sources, and the target dir was
+            // specified separately
+            PathBuf::from(target)
+        }
+        None => {
+            // If there was no explicit target-dir, then use the last
+            // path_arg
+            paths.pop().unwrap()
+        }
+    };
+
+    if options.strip_trailing_slashes {
+        for source in paths.iter_mut() {
+            *source = source.components().as_path().to_owned()
+        }
+    }
+
+    Ok((paths, target))
+}
+
+fn preserve_hardlinks(
+    hard_links: &mut Vec<(String, u64)>,
+    source: &std::path::Path,
+    dest: std::path::PathBuf,
+    found_hard_link: &mut bool,
+) -> CopyResult<()> {
+    // Redox does not currently support hard links
+    #[cfg(not(target_os = "redox"))]
+    {
+        if !source.is_dir() {
+            unsafe {
+                let inode: u64;
+                let nlinks: u64;
+                #[cfg(unix)]
+                {
+                    let src_path = CString::new(source.as_os_str().to_str().unwrap()).unwrap();
+                    let mut stat = mem::zeroed();
+                    if libc::lstat(src_path.as_ptr(), &mut stat) < 0 {
+                        return Err(format!(
+                            "cannot stat {:?}: {}",
+                            src_path,
+                            std::io::Error::last_os_error()
+                        )
+                        .into());
+                    }
+                    inode = stat.st_ino as u64;
+                    nlinks = stat.st_nlink as u64;
+                }
+                #[cfg(windows)]
+                {
+                    let src_path: Vec<u16> = OsStr::new(source).encode_wide().collect();
+                    #[allow(deprecated)]
+                    let stat = mem::uninitialized();
+                    let handle = CreateFileW(
+                        src_path.as_ptr(),
+                        winapi::um::winnt::GENERIC_READ,
+                        winapi::um::winnt::FILE_SHARE_READ,
+                        std::ptr::null_mut(),
+                        0,
+                        0,
+                        std::ptr::null_mut(),
+                    );
+                    if GetFileInformationByHandle(handle, stat) != 0 {
+                        return Err(format!(
+                            "cannot get file information {:?}: {}",
+                            source,
+                            std::io::Error::last_os_error()
+                        )
+                        .into());
+                    }
+                    inode = ((*stat).nFileIndexHigh as u64) << 32 | (*stat).nFileIndexLow as u64;
+                    nlinks = (*stat).nNumberOfLinks as u64;
+                }
+
+                for hard_link in hard_links.iter() {
+                    if hard_link.1 == inode {
+                        std::fs::hard_link(hard_link.0.clone(), dest.clone()).unwrap();
+                        *found_hard_link = true;
+                    }
+                }
+                if !(*found_hard_link) && nlinks > 1 {
+                    hard_links.push((dest.to_str().unwrap().to_string(), inode));
+                }
+            }
+        }
+    }
+    Ok(())
+}
+
+/// Copy all `sources` to `target`.  Returns an
+/// `Err(Error::NotAllFilesCopied)` if at least one non-fatal error was
+/// encountered.
+///
+/// Behavior depends on `options`, see [`Options`] for details.
+///
+/// [`Options`]: ./struct.Options.html
+fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResult<()> {
+    let target_type = TargetType::determine(sources, target);
+    verify_target_type(target, &target_type)?;
+
+    let mut preserve_hard_links = false;
+    for attribute in &options.preserve_attributes {
+        if *attribute == Attribute::Links {
+            preserve_hard_links = true;
+        }
+    }
+
+    let mut hard_links: Vec<(String, u64)> = vec![];
+
+    let mut non_fatal_errors = false;
+    let mut seen_sources = HashSet::with_capacity(sources.len());
+    for source in sources {
+        if seen_sources.contains(source) {
+            show_warning!("source '{}' specified more than once", source.display());
+        } else {
+            let mut found_hard_link = false;
+            if preserve_hard_links {
+                let dest = construct_dest_path(source, target, &target_type, options)?;
+                preserve_hardlinks(&mut hard_links, source, dest, &mut found_hard_link).unwrap();
+            }
+            if !found_hard_link {
+                if let Err(error) = copy_source(source, target, &target_type, options) {
+                    match error {
+                        // When using --no-clobber, we don't want to show
+                        // an error message
+                        Error::NotAllFilesCopied => (),
+                        Error::Skipped(_) => {
+                            show_error!("{}", error);
+                        }
+                        _ => {
+                            show_error!("{}", error);
+                            non_fatal_errors = true
+                        }
+                    }
+                }
+            }
+            seen_sources.insert(source);
+        }
+    }
+    if non_fatal_errors {
+        Err(Error::NotAllFilesCopied)
+    } else {
+        Ok(())
+    }
+}
+
+fn construct_dest_path(
+    source_path: &Path,
+    target: &TargetSlice,
+    target_type: &TargetType,
+    options: &Options,
+) -> CopyResult<PathBuf> {
+    if options.no_target_dir && target.is_dir() {
+        return Err(format!(
+            "cannot overwrite directory '{}' with non-directory",
+            target.display()
+        )
+        .into());
+    }
+
+    if options.parents && !target.is_dir() {
+        return Err("with --parents, the destination must be a directory".into());
+    }
+
+    Ok(match *target_type {
+        TargetType::Directory => {
+            let root = if options.parents {
+                Path::new("")
+            } else {
+                source_path.parent().unwrap_or(source_path)
+            };
+            localize_to_target(root, source_path, target)?
+        }
+        TargetType::File => target.to_path_buf(),
+    })
+}
+
+fn copy_source(
+    source: &SourceSlice,
+    target: &TargetSlice,
+    target_type: &TargetType,
+    options: &Options,
+) -> CopyResult<()> {
+    let source_path = Path::new(&source);
+    if source_path.is_dir() {
+        // Copy as directory
+        copy_directory(source, target, options)
+    } else {
+        // Copy as file
+        let dest = construct_dest_path(source_path, target, target_type, options)?;
+        copy_file(source_path, dest.as_path(), options)
+    }
+}
+
+#[cfg(target_os = "windows")]
+fn adjust_canonicalization(p: &Path) -> Cow<Path> {
+    // In some cases, \\? can be missing on some Windows paths.  Add it at the
+    // beginning unless the path is prefixed with a device namespace.
+    const VERBATIM_PREFIX: &str = r#"\\?"#;
+    const DEVICE_NS_PREFIX: &str = r#"\\."#;
+
+    let has_prefix = p
+        .components()
+        .next()
+        .and_then(|comp| comp.as_os_str().to_str())
+        .map(|p_str| p_str.starts_with(VERBATIM_PREFIX) || p_str.starts_with(DEVICE_NS_PREFIX))
+        .unwrap_or_default();
+
+    if has_prefix {
+        p.into()
+    } else {
+        Path::new(VERBATIM_PREFIX).join(p).into()
+    }
+}
+
+/// Read the contents of the directory `root` and recursively copy the
+/// contents to `target`.
+///
+/// Any errors encountered copying files in the tree will be logged but
+/// will not cause a short-circuit.
+fn copy_directory(root: &Path, target: &TargetSlice, options: &Options) -> CopyResult<()> {
+    if !options.recursive {
+        return Err(format!("omitting directory '{}'", root.display()).into());
+    }
+
+    // if no-dereference is enabled and this is a symlink, copy it as a file
+    if !options.dereference && fs::symlink_metadata(root).unwrap().file_type().is_symlink() {
+        return copy_file(root, target, options);
+    }
+
+    let current_dir =
+        env::current_dir().unwrap_or_else(|e| crash!(1, "failed to get current directory {}", e));
+
+    let root_path = current_dir.join(root);
+
+    let root_parent = if target.exists() {
+        root_path.parent()
+    } else {
+        Some(root_path.as_path())
+    };
+
+    #[cfg(unix)]
+    let mut hard_links: Vec<(String, u64)> = vec![];
+    let mut preserve_hard_links = false;
+    for attribute in &options.preserve_attributes {
+        if *attribute == Attribute::Links {
+            preserve_hard_links = true;
+        }
+    }
+
+    // This should be changed once Redox supports hardlinks
+    #[cfg(any(windows, target_os = "redox"))]
+    let mut hard_links: Vec<(String, u64)> = vec![];
+
+    for path in WalkDir::new(root)
+        .same_file_system(options.one_file_system)
+        .follow_links(options.dereference)
+    {
+        let p = or_continue!(path);
+        let is_symlink = fs::symlink_metadata(p.path())?.file_type().is_symlink();
+        let path = current_dir.join(&p.path());
+
+        let local_to_root_parent = match root_parent {
+            Some(parent) => {
+                #[cfg(windows)]
+                {
+                    // On Windows, some paths are starting with \\?
+                    // but not always, so, make sure that we are consistent for strip_prefix
+                    // See https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file for more info
+                    let parent_can = adjust_canonicalization(parent);
+                    let path_can = adjust_canonicalization(&path);
+
+                    or_continue!(&path_can.strip_prefix(&parent_can)).to_path_buf()
+                }
+                #[cfg(not(windows))]
+                {
+                    or_continue!(path.strip_prefix(&parent)).to_path_buf()
+                }
+            }
+            None => path.clone(),
+        };
+
+        let local_to_target = target.join(&local_to_root_parent);
+        if is_symlink && !options.dereference {
+            copy_link(&path, &local_to_target)?;
+        } else if path.is_dir() && !local_to_target.exists() {
+            or_continue!(fs::create_dir_all(local_to_target));
+        } else if !path.is_dir() {
+            if preserve_hard_links {
+                let mut found_hard_link = false;
+                let source = path.to_path_buf();
+                let dest = local_to_target.as_path().to_path_buf();
+                preserve_hardlinks(&mut hard_links, &source, dest, &mut found_hard_link).unwrap();
+                if !found_hard_link {
+                    match copy_file(path.as_path(), local_to_target.as_path(), options) {
+                        Ok(_) => Ok(()),
+                        Err(err) => {
+                            if fs::symlink_metadata(&source)?.file_type().is_symlink() {
+                                // silent the error with a symlink
+                                // In case we do --archive, we might copy the symlink
+                                // before the file itself
+                                Ok(())
+                            } else {
+                                Err(err)
+                            }
+                        }
+                    }?;
+                }
+            } else {
+                copy_file(path.as_path(), local_to_target.as_path(), options)?;
+            }
+        }
+    }
+
+    Ok(())
+}
+
+impl OverwriteMode {
+    fn verify(&self, path: &Path) -> CopyResult<()> {
+        match *self {
+            OverwriteMode::NoClobber => Err(Error::NotAllFilesCopied),
+            OverwriteMode::Interactive(_) => {
+                if prompt_yes!("{}: overwrite {}? ", uucore::util_name(), path.display()) {
+                    Ok(())
+                } else {
+                    Err(Error::Skipped(format!(
+                        "Not overwriting {} at user request",
+                        path.display()
+                    )))
+                }
+            }
+            OverwriteMode::Clobber(_) => Ok(()),
+        }
+    }
+}
+
+fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResult<()> {
+    let context = &*format!("'{}' -> '{}'", source.display().to_string(), dest.display());
+    match *attribute {
+        #[cfg(unix)]
+        Attribute::Mode => {
+            let mode = fs::metadata(source).context(context)?.permissions().mode();
+            let mut dest_metadata = fs::metadata(source).context(context)?.permissions();
+            dest_metadata.set_mode(mode);
+        }
+        Attribute::Ownership => {
+            let metadata = fs::metadata(source).context(context)?;
+            fs::set_permissions(dest, metadata.permissions()).context(context)?;
+        }
+        Attribute::Timestamps => {
+            let metadata = fs::metadata(source)?;
+            filetime::set_file_times(
+                Path::new(dest),
+                FileTime::from_last_access_time(&metadata),
+                FileTime::from_last_modification_time(&metadata),
+            )?;
+        }
+        Attribute::Context => {}
+        Attribute::Links => {}
+        Attribute::Xattr => {
+            #[cfg(unix)]
+            {
+                let xattrs = xattr::list(source)?;
+                for attr in xattrs {
+                    if let Some(attr_value) = xattr::get(source, attr.clone())? {
+                        crash_if_err!(EXIT_ERR, xattr::set(dest, attr, &attr_value[..]));
+                    }
+                }
+            }
+            #[cfg(not(unix))]
+            {
+                return Err("XAttrs are only supported on unix.".to_string().into());
+            }
+        }
+    };
+
+    Ok(())
+}
+
+#[cfg(not(windows))]
+#[allow(clippy::unnecessary_wraps)] // needed for windows version
+fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
+    match std::os::unix::fs::symlink(source, dest).context(context) {
+        Ok(_) => Ok(()),
+        Err(_) => Ok(()),
+    }
+}
+
+#[cfg(windows)]
+fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
+    Ok(std::os::windows::fs::symlink_file(source, dest).context(context)?)
+}
+
+fn context_for(src: &Path, dest: &Path) -> String {
+    format!("'{}' -> '{}'", src.display(), dest.display())
+}
+
+/// Implements a simple backup copy for the destination file.
+/// TODO: for the backup, should this function be replaced by `copy_file(...)`?
+fn backup_dest(dest: &Path, backup_path: &Path) -> CopyResult<PathBuf> {
+    fs::copy(dest, &backup_path)?;
+    Ok(backup_path.into())
+}
+
+fn handle_existing_dest(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
+    if paths_refer_to_same_file(source, dest)? {
+        return Err(format!("{}: same file", context_for(source, dest)).into());
+    }
+
+    options.overwrite.verify(dest)?;
+
+    let backup_path = backup_control::get_backup_path(options.backup, dest, &options.backup_suffix);
+    if let Some(backup_path) = backup_path {
+        backup_dest(dest, &backup_path)?;
+    }
+
+    match options.overwrite {
+        OverwriteMode::Clobber(ClobberMode::Force) => {
+            if fs::metadata(dest)?.permissions().readonly() {
+                fs::remove_file(dest)?;
+            }
+        }
+        OverwriteMode::Clobber(ClobberMode::RemoveDestination) => {
+            fs::remove_file(dest)?;
+        }
+        _ => (),
+    };
+
+    Ok(())
+}
+
+/// Copy the a file from `source` to `dest`. No path manipulation is
+/// done on either `source` or `dest`, the are used as provided.
+///
+/// Behavior when copying to existing files is contingent on the
+/// `options.overwrite` mode. If a file is skipped, the return type
+/// should be `Error:Skipped`
+///
+/// The original permissions of `source` will be copied to `dest`
+/// after a successful copy.
+fn copy_file(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
+    if dest.exists() {
+        handle_existing_dest(source, dest, options)?;
+    }
+
+    if options.verbose {
+        println!("{}", context_for(source, dest));
+    }
+
+    #[allow(unused)]
+    {
+        // TODO: implement --preserve flag
+        let mut preserve_context = false;
+        for attribute in &options.preserve_attributes {
+            if *attribute == Attribute::Context {
+                preserve_context = true;
+            }
+        }
+    }
+    match options.copy_mode {
+        CopyMode::Link => {
+            fs::hard_link(source, dest).context(&*context_for(source, dest))?;
+        }
+        CopyMode::Copy => {
+            copy_helper(source, dest, options)?;
+        }
+        CopyMode::SymLink => {
+            symlink_file(source, dest, &*context_for(source, dest))?;
+        }
+        CopyMode::Sparse => return Err(Error::NotImplemented(options::SPARSE.to_string())),
+        CopyMode::Update => {
+            if dest.exists() {
+                let src_metadata = fs::metadata(source)?;
+                let dest_metadata = fs::metadata(dest)?;
+
+                let src_time = src_metadata.modified()?;
+                let dest_time = dest_metadata.modified()?;
+                if src_time <= dest_time {
+                    return Ok(());
+                } else {
+                    copy_helper(source, dest, options)?;
+                }
+            } else {
+                copy_helper(source, dest, options)?;
+            }
+        }
+        CopyMode::AttrOnly => {
+            OpenOptions::new()
+                .write(true)
+                .truncate(false)
+                .create(true)
+                .open(dest)
+                .unwrap();
+        }
+    };
+    for attribute in &options.preserve_attributes {
+        copy_attribute(source, dest, attribute)?;
+    }
+    Ok(())
+}
+
+/// Copy the file from `source` to `dest` either using the normal `fs::copy` or a
+/// copy-on-write scheme if --reflink is specified and the filesystem supports it.
+fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()> {
+    if options.parents {
+        let parent = dest.parent().unwrap_or(dest);
+        fs::create_dir_all(parent)?;
+    }
+    let is_symlink = fs::symlink_metadata(&source)?.file_type().is_symlink();
+    if source.to_string_lossy() == "/dev/null" {
+        /* workaround a limitation of fs::copy
+         * https://github.com/rust-lang/rust/issues/79390
+         */
+        File::create(dest)?;
+    } else if !options.dereference && is_symlink {
+        copy_link(source, dest)?;
+    } else if options.reflink_mode != ReflinkMode::Never {
+        #[cfg(not(any(target_os = "linux", target_os = "macos")))]
+        return Err("--reflink is only supported on linux and macOS"
+            .to_string()
+            .into());
+        #[cfg(any(target_os = "linux", target_os = "macos"))]
+        if is_symlink {
+            assert!(options.dereference);
+            let real_path = std::fs::read_link(source)?;
+
+            #[cfg(target_os = "macos")]
+            copy_on_write_macos(&real_path, dest, options.reflink_mode)?;
+            #[cfg(target_os = "linux")]
+            copy_on_write_linux(&real_path, dest, options.reflink_mode)?;
+        } else {
+            #[cfg(target_os = "macos")]
+            copy_on_write_macos(source, dest, options.reflink_mode)?;
+            #[cfg(target_os = "linux")]
+            copy_on_write_linux(source, dest, options.reflink_mode)?;
+        }
+    } else {
+        fs::copy(source, dest).context(&*context_for(source, dest))?;
+    }
+
+    Ok(())
+}
+
+fn copy_link(source: &Path, dest: &Path) -> CopyResult<()> {
+    // Here, we will copy the symlink itself (actually, just recreate it)
+    let link = fs::read_link(&source)?;
+    let dest: Cow<'_, Path> = if dest.is_dir() {
+        match source.file_name() {
+            Some(name) => dest.join(name).into(),
+            None => crash!(
+                EXIT_ERR,
+                "cannot stat '{}': No such file or directory",
+                source.display()
+            ),
+        }
+    } else {
+        // we always need to remove the file to be able to create a symlink,
+        // even if it is writeable.
+        if dest.exists() {
+            fs::remove_file(dest)?;
+        }
+        dest.into()
+    };
+    symlink_file(&link, &dest, &*context_for(&link, &dest))
+}
+
+/// Copies `source` to `dest` using copy-on-write if possible.
+#[cfg(target_os = "linux")]
+fn copy_on_write_linux(source: &Path, dest: &Path, mode: ReflinkMode) -> CopyResult<()> {
+    debug_assert!(mode != ReflinkMode::Never);
+
+    let src_file = File::open(source).context(&*context_for(source, dest))?;
+    let dst_file = OpenOptions::new()
+        .write(true)
+        .truncate(false)
+        .create(true)
+        .open(dest)
+        .context(&*context_for(source, dest))?;
+    match mode {
+        ReflinkMode::Always => unsafe {
+            let result = ficlone(dst_file.as_raw_fd(), src_file.as_raw_fd() as *const i32);
+            if result != 0 {
+                Err(format!(
+                    "failed to clone {:?} from {:?}: {}",
+                    source,
+                    dest,
+                    std::io::Error::last_os_error()
+                )
+                .into())
+            } else {
+                Ok(())
+            }
+        },
+        ReflinkMode::Auto => unsafe {
+            let result = ficlone(dst_file.as_raw_fd(), src_file.as_raw_fd() as *const i32);
+            if result != 0 {
+                fs::copy(source, dest).context(&*context_for(source, dest))?;
+            }
+            Ok(())
+        },
+        ReflinkMode::Never => unreachable!(),
+    }
+}
+
+/// Copies `source` to `dest` using copy-on-write if possible.
+#[cfg(target_os = "macos")]
+fn copy_on_write_macos(source: &Path, dest: &Path, mode: ReflinkMode) -> CopyResult<()> {
+    debug_assert!(mode != ReflinkMode::Never);
+
+    // Extract paths in a form suitable to be passed to a syscall.
+    // The unwrap() is safe because they come from the command-line and so contain non nul
+    // character.
+    use std::os::unix::ffi::OsStrExt;
+    let src = CString::new(source.as_os_str().as_bytes()).unwrap();
+    let dst = CString::new(dest.as_os_str().as_bytes()).unwrap();
+
+    // clonefile(2) was introduced in macOS 10.12 so we cannot statically link against it
+    // for backward compatibility.
+    let clonefile = CString::new("clonefile").unwrap();
+    let raw_pfn = unsafe { libc::dlsym(libc::RTLD_NEXT, clonefile.as_ptr()) };
+
+    let mut error = 0;
+    if !raw_pfn.is_null() {
+        // Call clonefile(2).
+        // Safety: Casting a C function pointer to a rust function value is one of the few
+        // blessed uses of `transmute()`.
+        unsafe {
+            let pfn: extern "C" fn(
+                src: *const libc::c_char,
+                dst: *const libc::c_char,
+                flags: u32,
+            ) -> libc::c_int = std::mem::transmute(raw_pfn);
+            error = pfn(src.as_ptr(), dst.as_ptr(), 0);
+            if std::io::Error::last_os_error().kind() == std::io::ErrorKind::AlreadyExists {
+                // clonefile(2) fails if the destination exists.  Remove it and try again.  Do not
+                // bother to check if removal worked because we're going to try to clone again.
+                let _ = fs::remove_file(dest);
+                error = pfn(src.as_ptr(), dst.as_ptr(), 0);
+            }
+        }
+    }
+
+    if raw_pfn.is_null() || error != 0 {
+        // clonefile(2) is either not supported or it errored out (possibly because the FS does not
+        // support COW).
+        match mode {
+            ReflinkMode::Always => {
+                return Err(
+                    format!("failed to clone {:?} from {:?}: {}", source, dest, error).into(),
+                )
+            }
+            ReflinkMode::Auto => fs::copy(source, dest).context(&*context_for(source, dest))?,
+            ReflinkMode::Never => unreachable!(),
+        };
+    }
+
+    Ok(())
+}
+
+/// Generate an error message if `target` is not the correct `target_type`
+pub fn verify_target_type(target: &Path, target_type: &TargetType) -> CopyResult<()> {
+    match (target_type, target.is_dir()) {
+        (&TargetType::Directory, false) => {
+            Err(format!("target: '{}' is not a directory", target.display()).into())
+        }
+        (&TargetType::File, true) => Err(format!(
+            "cannot overwrite directory '{}' with non-directory",
+            target.display()
+        )
+        .into()),
+        _ => Ok(()),
+    }
+}
+
+/// Remove the `root` prefix from `source` and prefix it with `target`
+/// to create a file that is local to `target`
+/// # Examples
+///
+/// ```ignore
+/// assert!(uu_cp::localize_to_target(
+///     &Path::new("a/source/"),
+///     &Path::new("a/source/c.txt"),
+///     &Path::new("target/"),
+/// ).unwrap() == Path::new("target/c.txt"))
+/// ```
+pub fn localize_to_target(root: &Path, source: &Path, target: &Path) -> CopyResult<PathBuf> {
+    let local_to_root = source.strip_prefix(&root)?;
+    Ok(target.join(&local_to_root))
+}
+
+pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::Result<bool> {
+    // We have to take symlinks and relative paths into account.
+    let pathbuf1 = canonicalize(p1, MissingHandling::Normal, ResolveMode::Logical)?;
+    let pathbuf2 = canonicalize(p2, MissingHandling::Normal, ResolveMode::Logical)?;
+
+    Ok(pathbuf1 == pathbuf2)
+}
+
+#[test]
+fn test_cp_localize_to_target() {
+    assert!(
+        localize_to_target(
+            Path::new("a/source/"),
+            Path::new("a/source/c.txt"),
+            Path::new("target/")
+        )
+        .unwrap()
+            == Path::new("target/c.txt")
+    )
+}
+
+
\ No newline at end of file diff --git a/src/uu_csplit/csplit.rs.html b/src/uu_csplit/csplit.rs.html new file mode 100644 index 000000000..ff4844ad8 --- /dev/null +++ b/src/uu_csplit/csplit.rs.html @@ -0,0 +1,1607 @@ +csplit.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+
+#![crate_name = "uu_csplit"]
+
+#[macro_use]
+extern crate uucore;
+use clap::{crate_version, App, Arg, ArgMatches};
+use regex::Regex;
+use std::cmp::Ordering;
+use std::io::{self, BufReader};
+use std::{
+    fs::{remove_file, File},
+    io::{BufRead, BufWriter, Write},
+};
+
+mod csplit_error;
+mod patterns;
+mod split_name;
+
+use crate::csplit_error::CsplitError;
+use crate::split_name::SplitName;
+use uucore::InvalidEncodingHandling;
+
+static SUMMARY: &str = "split a file into sections determined by context lines";
+static LONG_HELP: &str = "Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output.";
+
+mod options {
+    pub const SUFFIX_FORMAT: &str = "suffix-format";
+    pub const SUPPRESS_MATCHED: &str = "suppress-matched";
+    pub const DIGITS: &str = "digits";
+    pub const PREFIX: &str = "prefix";
+    pub const KEEP_FILES: &str = "keep-files";
+    pub const QUIET: &str = "quiet";
+    pub const ELIDE_EMPTY_FILES: &str = "elide-empty-files";
+    pub const FILE: &str = "file";
+    pub const PATTERN: &str = "pattern";
+}
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... FILE PATTERN...",
+        uucore::execution_phrase()
+    )
+}
+
+/// Command line options for csplit.
+pub struct CsplitOptions {
+    split_name: crate::SplitName,
+    keep_files: bool,
+    quiet: bool,
+    elide_empty_files: bool,
+    suppress_matched: bool,
+}
+
+impl CsplitOptions {
+    fn new(matches: &ArgMatches) -> CsplitOptions {
+        let keep_files = matches.is_present(options::KEEP_FILES);
+        let quiet = matches.is_present(options::QUIET);
+        let elide_empty_files = matches.is_present(options::ELIDE_EMPTY_FILES);
+        let suppress_matched = matches.is_present(options::SUPPRESS_MATCHED);
+
+        CsplitOptions {
+            split_name: crash_if_err!(
+                1,
+                SplitName::new(
+                    matches.value_of(options::PREFIX).map(str::to_string),
+                    matches.value_of(options::SUFFIX_FORMAT).map(str::to_string),
+                    matches.value_of(options::DIGITS).map(str::to_string)
+                )
+            ),
+            keep_files,
+            quiet,
+            elide_empty_files,
+            suppress_matched,
+        }
+    }
+}
+
+/// Splits a file into severals according to the command line patterns.
+///
+/// # Errors
+///
+/// - [`io::Error`] if there is some problem reading/writing from/to a file.
+/// - [`::CsplitError::LineOutOfRange`] if the line number pattern is larger than the number of input
+///   lines.
+/// - [`::CsplitError::LineOutOfRangeOnRepetition`], like previous but after applying the pattern
+///   more than once.
+/// - [`::CsplitError::MatchNotFound`] if no line matched a regular expression.
+/// - [`::CsplitError::MatchNotFoundOnRepetition`], like previous but after applying the pattern
+///   more than once.
+pub fn csplit<T>(
+    options: &CsplitOptions,
+    patterns: Vec<patterns::Pattern>,
+    input: T,
+) -> Result<(), CsplitError>
+where
+    T: BufRead,
+{
+    let mut input_iter = InputSplitter::new(input.lines().enumerate());
+    let mut split_writer = SplitWriter::new(options);
+    let ret = do_csplit(&mut split_writer, patterns, &mut input_iter);
+
+    // consume the rest
+    input_iter.rewind_buffer();
+    if let Some((_, line)) = input_iter.next() {
+        split_writer.new_writer()?;
+        split_writer.writeln(line?)?;
+        for (_, line) in input_iter {
+            split_writer.writeln(line?)?;
+        }
+        split_writer.finish_split();
+    }
+    // delete files on error by default
+    if ret.is_err() && !options.keep_files {
+        split_writer.delete_all_splits()?;
+    }
+    ret
+}
+
+fn do_csplit<I>(
+    split_writer: &mut SplitWriter,
+    patterns: Vec<patterns::Pattern>,
+    input_iter: &mut InputSplitter<I>,
+) -> Result<(), CsplitError>
+where
+    I: Iterator<Item = (usize, io::Result<String>)>,
+{
+    // split the file based on patterns
+    for pattern in patterns.into_iter() {
+        let pattern_as_str = pattern.to_string();
+        let is_skip = matches!(pattern, patterns::Pattern::SkipToMatch(_, _, _));
+        match pattern {
+            patterns::Pattern::UpToLine(n, ex) => {
+                let mut up_to_line = n;
+                for (_, ith) in ex.iter() {
+                    split_writer.new_writer()?;
+                    match split_writer.do_to_line(&pattern_as_str, up_to_line, input_iter) {
+                        // the error happened when applying the pattern more than once
+                        Err(CsplitError::LineOutOfRange(_)) if ith != 1 => {
+                            return Err(CsplitError::LineOutOfRangeOnRepetition(
+                                pattern_as_str.to_string(),
+                                ith - 1,
+                            ));
+                        }
+                        Err(err) => return Err(err),
+                        // continue the splitting process
+                        Ok(()) => (),
+                    }
+                    up_to_line += n;
+                }
+            }
+            patterns::Pattern::UpToMatch(regex, offset, ex)
+            | patterns::Pattern::SkipToMatch(regex, offset, ex) => {
+                for (max, ith) in ex.iter() {
+                    if is_skip {
+                        // when skipping a part of the input, no writer is created
+                        split_writer.as_dev_null();
+                    } else {
+                        split_writer.new_writer()?;
+                    }
+                    match (
+                        split_writer.do_to_match(&pattern_as_str, &regex, offset, input_iter),
+                        max,
+                    ) {
+                        // in case of ::pattern::ExecutePattern::Always, then it's fine not to find a
+                        // matching line
+                        (Err(CsplitError::MatchNotFound(_)), None) => {
+                            return Ok(());
+                        }
+                        // the error happened when applying the pattern more than once
+                        (Err(CsplitError::MatchNotFound(_)), Some(m)) if m != 1 && ith != 1 => {
+                            return Err(CsplitError::MatchNotFoundOnRepetition(
+                                pattern_as_str.to_string(),
+                                ith - 1,
+                            ));
+                        }
+                        (Err(err), _) => return Err(err),
+                        // continue the splitting process
+                        (Ok(()), _) => (),
+                    };
+                }
+            }
+        };
+    }
+    Ok(())
+}
+
+/// Write a portion of the input file into a split which filename is based on an incrementing
+/// counter.
+struct SplitWriter<'a> {
+    /// the options set through the command line
+    options: &'a CsplitOptions,
+    /// a split counter
+    counter: usize,
+    /// the writer to the current split
+    current_writer: Option<BufWriter<File>>,
+    /// the size in bytes of the current split
+    size: usize,
+    /// flag to indicate that no content should be written to a split
+    dev_null: bool,
+}
+
+impl<'a> Drop for SplitWriter<'a> {
+    fn drop(&mut self) {
+        if self.options.elide_empty_files && self.size == 0 {
+            let file_name = self.options.split_name.get(self.counter);
+            remove_file(file_name).expect("Failed to elide split");
+        }
+    }
+}
+
+impl<'a> SplitWriter<'a> {
+    fn new(options: &CsplitOptions) -> SplitWriter {
+        SplitWriter {
+            options,
+            counter: 0,
+            current_writer: None,
+            size: 0,
+            dev_null: false,
+        }
+    }
+
+    /// Creates a new split and returns its filename.
+    ///
+    /// # Errors
+    ///
+    /// The creation of the split file may fail with some [`io::Error`].
+    fn new_writer(&mut self) -> io::Result<()> {
+        let file_name = self.options.split_name.get(self.counter);
+        let file = File::create(&file_name)?;
+        self.current_writer = Some(BufWriter::new(file));
+        self.counter += 1;
+        self.size = 0;
+        self.dev_null = false;
+        Ok(())
+    }
+
+    /// The current split will not keep any of the read input lines.
+    fn as_dev_null(&mut self) {
+        self.dev_null = true;
+    }
+
+    /// Writes the line to the current split, appending a newline character.
+    /// If [`dev_null`] is true, then the line is discarded.
+    ///
+    /// # Errors
+    ///
+    /// Some [`io::Error`] may occur when attempting to write the line.
+    fn writeln(&mut self, line: String) -> io::Result<()> {
+        if !self.dev_null {
+            match self.current_writer {
+                Some(ref mut current_writer) => {
+                    let bytes = line.as_bytes();
+                    current_writer.write_all(bytes)?;
+                    current_writer.write_all(b"\n")?;
+                    self.size += bytes.len() + 1;
+                }
+                None => panic!("trying to write to a split that was not created"),
+            }
+        }
+        Ok(())
+    }
+
+    /// Perform some operations after completing a split, i.e., either remove it
+    /// if the [`::ELIDE_EMPTY_FILES_OPT`] option is enabled, or print how much bytes were written
+    /// to it if [`::QUIET_OPT`] is disabled.
+    ///
+    /// # Errors
+    ///
+    /// Some [`io::Error`] if the split could not be removed in case it should be elided.
+    fn finish_split(&mut self) {
+        if !self.dev_null {
+            if self.options.elide_empty_files && self.size == 0 {
+                self.counter -= 1;
+            } else if !self.options.quiet {
+                println!("{}", self.size);
+            }
+        }
+    }
+
+    /// Removes all the split files that were created.
+    ///
+    /// # Errors
+    ///
+    /// Returns an [`io::Error`] if there was a problem removing a split.
+    fn delete_all_splits(&self) -> io::Result<()> {
+        let mut ret = Ok(());
+        for ith in 0..self.counter {
+            let file_name = self.options.split_name.get(ith);
+            if let Err(err) = remove_file(file_name) {
+                ret = Err(err);
+            }
+        }
+        ret
+    }
+
+    /// Split the input stream up to the line number `n`.
+    ///
+    /// If the line number `n` is smaller than the current position in the input, then an empty
+    /// split is created.
+    ///
+    /// # Errors
+    ///
+    /// In addition to errors reading/writing from/to a file, if the line number
+    /// `n` is greater than the total available lines, then a
+    /// [`::CsplitError::LineOutOfRange`] error is returned.
+    fn do_to_line<I>(
+        &mut self,
+        pattern_as_str: &str,
+        n: usize,
+        input_iter: &mut InputSplitter<I>,
+    ) -> Result<(), CsplitError>
+    where
+        I: Iterator<Item = (usize, io::Result<String>)>,
+    {
+        input_iter.rewind_buffer();
+        input_iter.set_size_of_buffer(1);
+
+        let mut ret = Err(CsplitError::LineOutOfRange(pattern_as_str.to_string()));
+        while let Some((ln, line)) = input_iter.next() {
+            let l = line?;
+            match n.cmp(&(&ln + 1)) {
+                Ordering::Less => {
+                    if input_iter.add_line_to_buffer(ln, l).is_some() {
+                        panic!("the buffer is big enough to contain 1 line");
+                    }
+                    ret = Ok(());
+                    break;
+                }
+                Ordering::Equal => {
+                    if !self.options.suppress_matched
+                        && input_iter.add_line_to_buffer(ln, l).is_some()
+                    {
+                        panic!("the buffer is big enough to contain 1 line");
+                    }
+                    ret = Ok(());
+                    break;
+                }
+                Ordering::Greater => (),
+            }
+            self.writeln(l)?;
+        }
+        self.finish_split();
+        ret
+    }
+
+    /// Read lines up to the line matching a [`Regex`]. With a non-zero offset,
+    /// the block of relevant lines can be extended (if positive), or reduced
+    /// (if negative).
+    ///
+    /// # Errors
+    ///
+    /// In addition to errors reading/writing from/to a file, the following errors may be returned:
+    /// - if no line matched, an [`::CsplitError::MatchNotFound`].
+    /// - if there are not enough lines to accommodate the offset, an
+    /// [`::CsplitError::LineOutOfRange`].
+    fn do_to_match<I>(
+        &mut self,
+        pattern_as_str: &str,
+        regex: &Regex,
+        mut offset: i32,
+        input_iter: &mut InputSplitter<I>,
+    ) -> Result<(), CsplitError>
+    where
+        I: Iterator<Item = (usize, io::Result<String>)>,
+    {
+        if offset >= 0 {
+            // The offset is zero or positive, no need for a buffer on the lines read.
+            // NOTE: drain the buffer of input_iter, no match should be done within.
+            for line in input_iter.drain_buffer() {
+                self.writeln(line)?;
+            }
+            // retain the matching line
+            input_iter.set_size_of_buffer(1);
+
+            while let Some((ln, line)) = input_iter.next() {
+                let l = line?;
+                if regex.is_match(&l) {
+                    match (self.options.suppress_matched, offset) {
+                        // no offset, add the line to the next split
+                        (false, 0) => {
+                            if input_iter.add_line_to_buffer(ln, l).is_some() {
+                                panic!("the buffer is big enough to contain 1 line");
+                            }
+                        }
+                        // a positive offset, some more lines need to be added to the current split
+                        (false, _) => self.writeln(l)?,
+                        _ => (),
+                    };
+                    offset -= 1;
+
+                    // write the extra lines required by the offset
+                    while offset > 0 {
+                        match input_iter.next() {
+                            Some((_, line)) => {
+                                self.writeln(line?)?;
+                            }
+                            None => {
+                                self.finish_split();
+                                return Err(CsplitError::LineOutOfRange(
+                                    pattern_as_str.to_string(),
+                                ));
+                            }
+                        };
+                        offset -= 1;
+                    }
+                    self.finish_split();
+                    return Ok(());
+                }
+                self.writeln(l)?;
+            }
+        } else {
+            // With a negative offset we use a buffer to keep the lines within the offset.
+            // NOTE: do not drain the buffer of input_iter, in case of an LineOutOfRange error
+            // but do not rewind it either since no match should be done within.
+            // The consequence is that the buffer may already be full with lines from a previous
+            // split, which is taken care of when calling `shrink_buffer_to_size`.
+            let offset_usize = -offset as usize;
+            input_iter.set_size_of_buffer(offset_usize);
+            while let Some((ln, line)) = input_iter.next() {
+                let l = line?;
+                if regex.is_match(&l) {
+                    for line in input_iter.shrink_buffer_to_size() {
+                        self.writeln(line)?;
+                    }
+                    if !self.options.suppress_matched {
+                        // add 1 to the buffer size to make place for the matched line
+                        input_iter.set_size_of_buffer(offset_usize + 1);
+                        if input_iter.add_line_to_buffer(ln, l).is_some() {
+                            panic!("should be big enough to hold every lines");
+                        }
+                    }
+                    self.finish_split();
+                    if input_iter.buffer_len() < offset_usize {
+                        return Err(CsplitError::LineOutOfRange(pattern_as_str.to_string()));
+                    }
+                    return Ok(());
+                }
+                if let Some(line) = input_iter.add_line_to_buffer(ln, l) {
+                    self.writeln(line)?;
+                }
+            }
+            // no match, drain the buffer into the current split
+            for line in input_iter.drain_buffer() {
+                self.writeln(line)?;
+            }
+        }
+
+        self.finish_split();
+        Err(CsplitError::MatchNotFound(pattern_as_str.to_string()))
+    }
+}
+
+/// An iterator which can output items from a buffer filled externally.
+/// This is used to pass matching lines to the next split and to support patterns with a negative offset.
+struct InputSplitter<I>
+where
+    I: Iterator<Item = (usize, io::Result<String>)>,
+{
+    iter: I,
+    buffer: Vec<<I as Iterator>::Item>,
+    /// the number of elements the buffer may hold
+    size: usize,
+    /// flag to indicate content off the buffer should be returned instead of off the wrapped
+    /// iterator
+    rewind: bool,
+}
+
+impl<I> InputSplitter<I>
+where
+    I: Iterator<Item = (usize, io::Result<String>)>,
+{
+    fn new(iter: I) -> InputSplitter<I> {
+        InputSplitter {
+            iter,
+            buffer: Vec::new(),
+            rewind: false,
+            size: 1,
+        }
+    }
+
+    /// Rewind the iteration by outputting the buffer's content.
+    fn rewind_buffer(&mut self) {
+        self.rewind = true;
+    }
+
+    /// Shrink the buffer so that its length is equal to the set size, returning an iterator for
+    /// the elements that were too much.
+    fn shrink_buffer_to_size(&mut self) -> impl Iterator<Item = String> + '_ {
+        let shrink_offset = if self.buffer.len() > self.size {
+            self.buffer.len() - self.size
+        } else {
+            0
+        };
+        self.buffer
+            .drain(..shrink_offset)
+            .map(|(_, line)| line.unwrap())
+    }
+
+    /// Drain the content of the buffer.
+    fn drain_buffer(&mut self) -> impl Iterator<Item = String> + '_ {
+        self.buffer.drain(..).map(|(_, line)| line.unwrap())
+    }
+
+    /// Set the maximum number of lines to keep.
+    fn set_size_of_buffer(&mut self, size: usize) {
+        self.size = size;
+    }
+
+    /// Add a line to the buffer. If the buffer has [`size`] elements, then its head is removed and
+    /// the new line is pushed to the buffer. The removed head is then available in the returned
+    /// option.
+    fn add_line_to_buffer(&mut self, ln: usize, line: String) -> Option<String> {
+        if self.rewind {
+            self.buffer.insert(0, (ln, Ok(line)));
+            None
+        } else if self.buffer.len() >= self.size {
+            let (_, head_line) = self.buffer.remove(0);
+            self.buffer.push((ln, Ok(line)));
+            Some(head_line.unwrap())
+        } else {
+            self.buffer.push((ln, Ok(line)));
+            None
+        }
+    }
+
+    /// Returns the number of lines stored in the buffer
+    fn buffer_len(&self) -> usize {
+        self.buffer.len()
+    }
+}
+
+impl<I> Iterator for InputSplitter<I>
+where
+    I: Iterator<Item = (usize, io::Result<String>)>,
+{
+    type Item = <I as Iterator>::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.rewind {
+            if !self.buffer.is_empty() {
+                return Some(self.buffer.remove(0));
+            }
+            self.rewind = false;
+        }
+        self.iter.next()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn input_splitter() {
+        let input = vec![
+            Ok(String::from("aaa")),
+            Ok(String::from("bbb")),
+            Ok(String::from("ccc")),
+            Ok(String::from("ddd")),
+        ];
+        let mut input_splitter = InputSplitter::new(input.into_iter().enumerate());
+
+        input_splitter.set_size_of_buffer(2);
+        assert_eq!(input_splitter.buffer_len(), 0);
+
+        match input_splitter.next() {
+            Some((0, Ok(line))) => {
+                assert_eq!(line, String::from("aaa"));
+                assert_eq!(input_splitter.add_line_to_buffer(0, line), None);
+                assert_eq!(input_splitter.buffer_len(), 1);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((1, Ok(line))) => {
+                assert_eq!(line, String::from("bbb"));
+                assert_eq!(input_splitter.add_line_to_buffer(1, line), None);
+                assert_eq!(input_splitter.buffer_len(), 2);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((2, Ok(line))) => {
+                assert_eq!(line, String::from("ccc"));
+                assert_eq!(
+                    input_splitter.add_line_to_buffer(2, line),
+                    Some(String::from("aaa"))
+                );
+                assert_eq!(input_splitter.buffer_len(), 2);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        input_splitter.rewind_buffer();
+
+        match input_splitter.next() {
+            Some((1, Ok(line))) => {
+                assert_eq!(line, String::from("bbb"));
+                assert_eq!(input_splitter.buffer_len(), 1);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((2, Ok(line))) => {
+                assert_eq!(line, String::from("ccc"));
+                assert_eq!(input_splitter.buffer_len(), 0);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((3, Ok(line))) => {
+                assert_eq!(line, String::from("ddd"));
+                assert_eq!(input_splitter.buffer_len(), 0);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        assert!(input_splitter.next().is_none());
+    }
+
+    #[test]
+    fn input_splitter_interrupt_rewind() {
+        let input = vec![
+            Ok(String::from("aaa")),
+            Ok(String::from("bbb")),
+            Ok(String::from("ccc")),
+            Ok(String::from("ddd")),
+        ];
+        let mut input_splitter = InputSplitter::new(input.into_iter().enumerate());
+
+        input_splitter.set_size_of_buffer(3);
+        assert_eq!(input_splitter.buffer_len(), 0);
+
+        match input_splitter.next() {
+            Some((0, Ok(line))) => {
+                assert_eq!(line, String::from("aaa"));
+                assert_eq!(input_splitter.add_line_to_buffer(0, line), None);
+                assert_eq!(input_splitter.buffer_len(), 1);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((1, Ok(line))) => {
+                assert_eq!(line, String::from("bbb"));
+                assert_eq!(input_splitter.add_line_to_buffer(1, line), None);
+                assert_eq!(input_splitter.buffer_len(), 2);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((2, Ok(line))) => {
+                assert_eq!(line, String::from("ccc"));
+                assert_eq!(input_splitter.add_line_to_buffer(2, line), None);
+                assert_eq!(input_splitter.buffer_len(), 3);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        input_splitter.rewind_buffer();
+
+        match input_splitter.next() {
+            Some((0, Ok(line))) => {
+                assert_eq!(line, String::from("aaa"));
+                assert_eq!(input_splitter.add_line_to_buffer(0, line), None);
+                assert_eq!(input_splitter.buffer_len(), 3);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((0, Ok(line))) => {
+                assert_eq!(line, String::from("aaa"));
+                assert_eq!(input_splitter.buffer_len(), 2);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((1, Ok(line))) => {
+                assert_eq!(line, String::from("bbb"));
+                assert_eq!(input_splitter.buffer_len(), 1);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((2, Ok(line))) => {
+                assert_eq!(line, String::from("ccc"));
+                assert_eq!(input_splitter.buffer_len(), 0);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        match input_splitter.next() {
+            Some((3, Ok(line))) => {
+                assert_eq!(line, String::from("ddd"));
+                assert_eq!(input_splitter.buffer_len(), 0);
+            }
+            item => panic!("wrong item: {:?}", item),
+        };
+
+        assert!(input_splitter.next().is_none());
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    // get the file to split
+    let file_name = matches.value_of(options::FILE).unwrap();
+
+    // get the patterns to split on
+    let patterns: Vec<String> = matches
+        .values_of(options::PATTERN)
+        .unwrap()
+        .map(str::to_string)
+        .collect();
+    let patterns = return_if_err!(1, patterns::get_patterns(&patterns[..]));
+    let options = CsplitOptions::new(&matches);
+    if file_name == "-" {
+        let stdin = io::stdin();
+        crash_if_err!(1, csplit(&options, patterns, stdin.lock()));
+    } else {
+        let file = return_if_err!(1, File::open(file_name));
+        let file_metadata = return_if_err!(1, file.metadata());
+        if !file_metadata.is_file() {
+            crash!(1, "'{}' is not a regular file", file_name);
+        }
+        crash_if_err!(1, csplit(&options, patterns, BufReader::new(file)));
+    };
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(SUMMARY)
+        .arg(
+            Arg::with_name(options::SUFFIX_FORMAT)
+                .short("b")
+                .long(options::SUFFIX_FORMAT)
+                .value_name("FORMAT")
+                .help("use sprintf FORMAT instead of %02d"),
+        )
+        .arg(
+            Arg::with_name(options::PREFIX)
+                .short("f")
+                .long(options::PREFIX)
+                .value_name("PREFIX")
+                .help("use PREFIX instead of 'xx'"),
+        )
+        .arg(
+            Arg::with_name(options::KEEP_FILES)
+                .short("k")
+                .long(options::KEEP_FILES)
+                .help("do not remove output files on errors"),
+        )
+        .arg(
+            Arg::with_name(options::SUPPRESS_MATCHED)
+                .long(options::SUPPRESS_MATCHED)
+                .help("suppress the lines matching PATTERN"),
+        )
+        .arg(
+            Arg::with_name(options::DIGITS)
+                .short("n")
+                .long(options::DIGITS)
+                .value_name("DIGITS")
+                .help("use specified number of digits instead of 2"),
+        )
+        .arg(
+            Arg::with_name(options::QUIET)
+                .short("s")
+                .long(options::QUIET)
+                .visible_alias("silent")
+                .help("do not print counts of output file sizes"),
+        )
+        .arg(
+            Arg::with_name(options::ELIDE_EMPTY_FILES)
+                .short("z")
+                .long(options::ELIDE_EMPTY_FILES)
+                .help("remove empty output files"),
+        )
+        .arg(Arg::with_name(options::FILE).hidden(true).required(true))
+        .arg(
+            Arg::with_name(options::PATTERN)
+                .hidden(true)
+                .multiple(true)
+                .required(true),
+        )
+        .after_help(LONG_HELP)
+}
+
+
\ No newline at end of file diff --git a/src/uu_csplit/csplit_error.rs.html b/src/uu_csplit/csplit_error.rs.html new file mode 100644 index 000000000..b0af3f84c --- /dev/null +++ b/src/uu_csplit/csplit_error.rs.html @@ -0,0 +1,75 @@ +csplit_error.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+
+use std::io;
+use thiserror::Error;
+
+/// Errors thrown by the csplit command
+#[derive(Debug, Error)]
+pub enum CsplitError {
+    #[error("IO error: {}", _0)]
+    IoError(io::Error),
+    #[error("'{}': line number out of range", _0)]
+    LineOutOfRange(String),
+    #[error("'{}': line number out of range on repetition {}", _0, _1)]
+    LineOutOfRangeOnRepetition(String, usize),
+    #[error("'{}': match not found", _0)]
+    MatchNotFound(String),
+    #[error("'{}': match not found on repetition {}", _0, _1)]
+    MatchNotFoundOnRepetition(String, usize),
+    #[error("line number must be greater than zero")]
+    LineNumberIsZero,
+    #[error("line number '{}' is smaller than preceding line number, {}", _0, _1)]
+    LineNumberSmallerThanPrevious(usize, usize),
+    #[error("invalid pattern: {}", _0)]
+    InvalidPattern(String),
+    #[error("invalid number: '{}'", _0)]
+    InvalidNumber(String),
+    #[error("incorrect conversion specification in suffix")]
+    SuffixFormatIncorrect,
+    #[error("too many % conversion specifications in suffix")]
+    SuffixFormatTooManyPercents,
+}
+
+impl From<io::Error> for CsplitError {
+    fn from(error: io::Error) -> Self {
+        CsplitError::IoError(error)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_csplit/patterns.rs.html b/src/uu_csplit/patterns.rs.html new file mode 100644 index 000000000..d9b7d2756 --- /dev/null +++ b/src/uu_csplit/patterns.rs.html @@ -0,0 +1,703 @@ +patterns.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+
+// spell-checker:ignore (regex) SKIPTO UPTO ; (vars) ntimes
+
+use crate::csplit_error::CsplitError;
+use regex::Regex;
+
+/// The definition of a pattern to match on a line.
+#[derive(Debug)]
+pub enum Pattern {
+    /// Copy the file's content to a split up to, not including, the given line number. The number
+    /// of times the pattern is executed is detailed in [`ExecutePattern`].
+    UpToLine(usize, ExecutePattern),
+    /// Copy the file's content to a split up to, not including, the line matching the regex. The
+    /// integer is an offset relative to the matched line of what to include (if positive) or
+    /// to exclude (if negative). The number of times the pattern is executed is detailed in
+    /// [`ExecutePattern`].
+    UpToMatch(Regex, i32, ExecutePattern),
+    /// Skip the file's content up to, not including, the line matching the regex. The integer
+    /// is an offset relative to the matched line of what to include (if positive) or to exclude
+    /// (if negative). The number of times the pattern is executed is detailed in [`ExecutePattern`].
+    SkipToMatch(Regex, i32, ExecutePattern),
+}
+
+impl ToString for Pattern {
+    fn to_string(&self) -> String {
+        match self {
+            Pattern::UpToLine(n, _) => n.to_string(),
+            Pattern::UpToMatch(regex, 0, _) => format!("/{}/", regex.as_str()),
+            Pattern::UpToMatch(regex, offset, _) => format!("/{}/{:+}", regex.as_str(), offset),
+            Pattern::SkipToMatch(regex, 0, _) => format!("%{}%", regex.as_str()),
+            Pattern::SkipToMatch(regex, offset, _) => format!("%{}%{:+}", regex.as_str(), offset),
+        }
+    }
+}
+
+/// The number of times a pattern can be used.
+#[derive(Debug)]
+pub enum ExecutePattern {
+    /// Execute the pattern as many times as possible
+    Always,
+    /// Execute the pattern a fixed number of times
+    Times(usize),
+}
+
+impl ExecutePattern {
+    pub fn iter(&self) -> ExecutePatternIter {
+        match self {
+            ExecutePattern::Times(n) => ExecutePatternIter::new(Some(*n)),
+            ExecutePattern::Always => ExecutePatternIter::new(None),
+        }
+    }
+}
+
+pub struct ExecutePatternIter {
+    max: Option<usize>,
+    cur: usize,
+}
+
+impl ExecutePatternIter {
+    fn new(max: Option<usize>) -> ExecutePatternIter {
+        ExecutePatternIter { max, cur: 0 }
+    }
+}
+
+impl Iterator for ExecutePatternIter {
+    type Item = (Option<usize>, usize);
+
+    fn next(&mut self) -> Option<(Option<usize>, usize)> {
+        match self.max {
+            // iterate until m is reached
+            Some(m) => {
+                if self.cur == m {
+                    None
+                } else {
+                    self.cur += 1;
+                    Some((self.max, self.cur))
+                }
+            }
+            // no limit, just increment a counter
+            None => {
+                self.cur += 1;
+                Some((None, self.cur))
+            }
+        }
+    }
+}
+
+/// Parses the definitions of patterns given on the command line into a list of [`Pattern`]s.
+///
+/// # Errors
+///
+/// If a pattern is incorrect, a [`::CsplitError::InvalidPattern`] error is returned, which may be
+/// due to, e.g.,:
+/// - an invalid regular expression;
+/// - an invalid number for, e.g., the offset.
+pub fn get_patterns(args: &[String]) -> Result<Vec<Pattern>, CsplitError> {
+    let patterns = extract_patterns(args)?;
+    validate_line_numbers(&patterns)?;
+    Ok(patterns)
+}
+
+fn extract_patterns(args: &[String]) -> Result<Vec<Pattern>, CsplitError> {
+    let mut patterns = Vec::with_capacity(args.len());
+    let to_match_reg =
+        Regex::new(r"^(/(?P<UPTO>.+)/|%(?P<SKIPTO>.+)%)(?P<OFFSET>[\+-]\d+)?$").unwrap();
+    let execute_ntimes_reg = Regex::new(r"^\{(?P<TIMES>\d+)|\*\}$").unwrap();
+    let mut iter = args.iter().peekable();
+
+    while let Some(arg) = iter.next() {
+        // get the number of times a pattern is repeated, which is at least once plus whatever is
+        // in the quantifier.
+        let execute_ntimes = match iter.peek() {
+            None => ExecutePattern::Times(1),
+            Some(&next_item) => {
+                match execute_ntimes_reg.captures(next_item) {
+                    None => ExecutePattern::Times(1),
+                    Some(r) => {
+                        // skip the next item
+                        iter.next();
+                        if let Some(times) = r.name("TIMES") {
+                            ExecutePattern::Times(times.as_str().parse::<usize>().unwrap() + 1)
+                        } else {
+                            ExecutePattern::Always
+                        }
+                    }
+                }
+            }
+        };
+
+        // get the pattern definition
+        if let Some(captures) = to_match_reg.captures(arg) {
+            let offset = match captures.name("OFFSET") {
+                None => 0,
+                Some(m) => m.as_str().parse().unwrap(),
+            };
+            if let Some(up_to_match) = captures.name("UPTO") {
+                let pattern = Regex::new(up_to_match.as_str())
+                    .map_err(|_| CsplitError::InvalidPattern(arg.to_string()))?;
+                patterns.push(Pattern::UpToMatch(pattern, offset, execute_ntimes));
+            } else if let Some(skip_to_match) = captures.name("SKIPTO") {
+                let pattern = Regex::new(skip_to_match.as_str())
+                    .map_err(|_| CsplitError::InvalidPattern(arg.to_string()))?;
+                patterns.push(Pattern::SkipToMatch(pattern, offset, execute_ntimes));
+            }
+        } else if let Ok(line_number) = arg.parse::<usize>() {
+            patterns.push(Pattern::UpToLine(line_number, execute_ntimes));
+        } else {
+            return Err(CsplitError::InvalidPattern(arg.to_string()));
+        }
+    }
+    Ok(patterns)
+}
+
+/// Asserts the line numbers are in increasing order, starting at 1.
+fn validate_line_numbers(patterns: &[Pattern]) -> Result<(), CsplitError> {
+    patterns
+        .iter()
+        .filter_map(|pattern| match pattern {
+            Pattern::UpToLine(line_number, _) => Some(line_number),
+            _ => None,
+        })
+        .try_fold(0, |prev_ln, &current_ln| match (prev_ln, current_ln) {
+            // a line number cannot be zero
+            (_, 0) => Err(CsplitError::LineNumberIsZero),
+            // two consecutive numbers should not be equal
+            (n, m) if n == m => {
+                show_warning!("line number '{}' is the same as preceding line number", n);
+                Ok(n)
+            }
+            // a number cannot be greater than the one that follows
+            (n, m) if n > m => Err(CsplitError::LineNumberSmallerThanPrevious(m, n)),
+            (_, m) => Ok(m),
+        })?;
+    Ok(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn bad_pattern() {
+        let input = vec!["bad".to_string()];
+        assert!(get_patterns(input.as_slice()).is_err());
+    }
+
+    #[test]
+    fn up_to_line_pattern() {
+        let input: Vec<String> = vec!["24", "42", "{*}", "50", "{4}"]
+            .into_iter()
+            .map(|v| v.to_string())
+            .collect();
+        let patterns = get_patterns(input.as_slice()).unwrap();
+        assert_eq!(patterns.len(), 3);
+        match patterns.get(0) {
+            Some(Pattern::UpToLine(24, ExecutePattern::Times(1))) => (),
+            _ => panic!("expected UpToLine pattern"),
+        };
+        match patterns.get(1) {
+            Some(Pattern::UpToLine(42, ExecutePattern::Always)) => (),
+            _ => panic!("expected UpToLine pattern"),
+        };
+        match patterns.get(2) {
+            Some(Pattern::UpToLine(50, ExecutePattern::Times(5))) => (),
+            _ => panic!("expected UpToLine pattern"),
+        };
+    }
+
+    #[test]
+    fn up_to_match_pattern() {
+        let input: Vec<String> = vec![
+            "/test1.*end$/",
+            "/test2.*end$/",
+            "{*}",
+            "/test3.*end$/",
+            "{4}",
+            "/test4.*end$/+3",
+            "/test5.*end$/-3",
+        ]
+        .into_iter()
+        .map(|v| v.to_string())
+        .collect();
+        let patterns = get_patterns(input.as_slice()).unwrap();
+        assert_eq!(patterns.len(), 5);
+        match patterns.get(0) {
+            Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(1))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test1.*end$");
+            }
+            _ => panic!("expected UpToMatch pattern"),
+        };
+        match patterns.get(1) {
+            Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Always)) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test2.*end$");
+            }
+            _ => panic!("expected UpToMatch pattern"),
+        };
+        match patterns.get(2) {
+            Some(Pattern::UpToMatch(reg, 0, ExecutePattern::Times(5))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test3.*end$");
+            }
+            _ => panic!("expected UpToMatch pattern"),
+        };
+        match patterns.get(3) {
+            Some(Pattern::UpToMatch(reg, 3, ExecutePattern::Times(1))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test4.*end$");
+            }
+            _ => panic!("expected UpToMatch pattern"),
+        };
+        match patterns.get(4) {
+            Some(Pattern::UpToMatch(reg, -3, ExecutePattern::Times(1))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test5.*end$");
+            }
+            _ => panic!("expected UpToMatch pattern"),
+        };
+    }
+
+    #[test]
+    fn skip_to_match_pattern() {
+        let input: Vec<String> = vec![
+            "%test1.*end$%",
+            "%test2.*end$%",
+            "{*}",
+            "%test3.*end$%",
+            "{4}",
+            "%test4.*end$%+3",
+            "%test5.*end$%-3",
+        ]
+        .into_iter()
+        .map(|v| v.to_string())
+        .collect();
+        let patterns = get_patterns(input.as_slice()).unwrap();
+        assert_eq!(patterns.len(), 5);
+        match patterns.get(0) {
+            Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(1))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test1.*end$");
+            }
+            _ => panic!("expected SkipToMatch pattern"),
+        };
+        match patterns.get(1) {
+            Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Always)) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test2.*end$");
+            }
+            _ => panic!("expected SkipToMatch pattern"),
+        };
+        match patterns.get(2) {
+            Some(Pattern::SkipToMatch(reg, 0, ExecutePattern::Times(5))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test3.*end$");
+            }
+            _ => panic!("expected SkipToMatch pattern"),
+        };
+        match patterns.get(3) {
+            Some(Pattern::SkipToMatch(reg, 3, ExecutePattern::Times(1))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test4.*end$");
+            }
+            _ => panic!("expected SkipToMatch pattern"),
+        };
+        match patterns.get(4) {
+            Some(Pattern::SkipToMatch(reg, -3, ExecutePattern::Times(1))) => {
+                let parsed_reg = format!("{}", reg);
+                assert_eq!(parsed_reg, "test5.*end$");
+            }
+            _ => panic!("expected SkipToMatch pattern"),
+        };
+    }
+
+    #[test]
+    fn line_number_zero() {
+        let patterns = vec![Pattern::UpToLine(0, ExecutePattern::Times(1))];
+        match validate_line_numbers(&patterns) {
+            Err(CsplitError::LineNumberIsZero) => (),
+            _ => panic!("expected LineNumberIsZero error"),
+        }
+    }
+
+    #[test]
+    fn line_number_smaller_than_previous() {
+        let input: Vec<String> = vec!["10".to_string(), "5".to_string()];
+        match get_patterns(input.as_slice()) {
+            Err(CsplitError::LineNumberSmallerThanPrevious(5, 10)) => (),
+            _ => panic!("expected LineNumberSmallerThanPrevious error"),
+        }
+    }
+
+    #[test]
+    fn line_number_smaller_than_previous_separate() {
+        let input: Vec<String> = vec!["10".to_string(), "/20/".to_string(), "5".to_string()];
+        match get_patterns(input.as_slice()) {
+            Err(CsplitError::LineNumberSmallerThanPrevious(5, 10)) => (),
+            _ => panic!("expected LineNumberSmallerThanPrevious error"),
+        }
+    }
+
+    #[test]
+    fn line_number_zero_separate() {
+        let input: Vec<String> = vec!["10".to_string(), "/20/".to_string(), "0".to_string()];
+        match get_patterns(input.as_slice()) {
+            Err(CsplitError::LineNumberIsZero) => (),
+            _ => panic!("expected LineNumberIsZero error"),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_csplit/split_name.rs.html b/src/uu_csplit/split_name.rs.html new file mode 100644 index 000000000..c9d5a42f9 --- /dev/null +++ b/src/uu_csplit/split_name.rs.html @@ -0,0 +1,845 @@ +split_name.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+
+// spell-checker:ignore (regex) diuox
+
+use regex::Regex;
+
+use crate::csplit_error::CsplitError;
+
+/// Computes the filename of a split, taking into consideration a possible user-defined suffix
+/// format.
+pub struct SplitName {
+    fn_split_name: Box<dyn Fn(usize) -> String>,
+}
+
+impl SplitName {
+    /// Creates a new SplitName with the given user-defined options:
+    /// - `prefix_opt` specifies a prefix for all splits.
+    /// - `format_opt` specifies a custom format for the suffix part of the filename, using the
+    /// `sprintf` format notation.
+    /// - `n_digits_opt` defines the width of the split number.
+    ///
+    /// # Caveats
+    ///
+    /// If `prefix_opt` and `format_opt` are defined, and the `format_opt` has some string appearing
+    /// before the conversion pattern (e.g., "here-%05d"), then it is appended to the passed prefix
+    /// via `prefix_opt`.
+    ///
+    /// If `n_digits_opt` and `format_opt` are defined, then width defined in `format_opt` is
+    /// taken.
+    pub fn new(
+        prefix_opt: Option<String>,
+        format_opt: Option<String>,
+        n_digits_opt: Option<String>,
+    ) -> Result<SplitName, CsplitError> {
+        // get the prefix
+        let prefix = prefix_opt.unwrap_or_else(|| "xx".to_string());
+        // the width for the split offset
+        let n_digits = n_digits_opt
+            .map(|opt| {
+                opt.parse::<usize>()
+                    .map_err(|_| CsplitError::InvalidNumber(opt))
+            })
+            .transpose()?
+            .unwrap_or(2);
+        // translate the custom format into a function
+        let fn_split_name: Box<dyn Fn(usize) -> String> = match format_opt {
+            None => Box::new(move |n: usize| -> String {
+                format!("{}{:0width$}", prefix, n, width = n_digits)
+            }),
+            Some(custom) => {
+                let spec =
+                    Regex::new(r"(?P<ALL>%((?P<FLAG>[0#-])(?P<WIDTH>\d+)?)?(?P<TYPE>[diuoxX]))")
+                        .unwrap();
+                let mut captures_iter = spec.captures_iter(&custom);
+                let custom_fn: Box<dyn Fn(usize) -> String> = match captures_iter.next() {
+                    Some(captures) => {
+                        let all = captures.name("ALL").unwrap();
+                        let before = custom[0..all.start()].to_owned();
+                        let after = custom[all.end()..].to_owned();
+                        let n_digits = match captures.name("WIDTH") {
+                            None => 0,
+                            Some(m) => m.as_str().parse::<usize>().unwrap(),
+                        };
+                        match (captures.name("FLAG"), captures.name("TYPE")) {
+                            (None, Some(ref t)) => match t.as_str() {
+                                "d" | "i" | "u" => Box::new(move |n: usize| -> String {
+                                    format!("{}{}{}{}", prefix, before, n, after)
+                                }),
+                                "o" => Box::new(move |n: usize| -> String {
+                                    format!("{}{}{:o}{}", prefix, before, n, after)
+                                }),
+                                "x" => Box::new(move |n: usize| -> String {
+                                    format!("{}{}{:x}{}", prefix, before, n, after)
+                                }),
+                                "X" => Box::new(move |n: usize| -> String {
+                                    format!("{}{}{:X}{}", prefix, before, n, after)
+                                }),
+                                _ => return Err(CsplitError::SuffixFormatIncorrect),
+                            },
+                            (Some(ref f), Some(ref t)) => {
+                                match (f.as_str(), t.as_str()) {
+                                    /*
+                                     * zero padding
+                                     */
+                                    // decimal
+                                    ("0", "d") | ("0", "i") | ("0", "u") => {
+                                        Box::new(move |n: usize| -> String {
+                                            format!(
+                                                "{}{}{:0width$}{}",
+                                                prefix,
+                                                before,
+                                                n,
+                                                after,
+                                                width = n_digits
+                                            )
+                                        })
+                                    }
+                                    // octal
+                                    ("0", "o") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:0width$o}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+                                    // lower hexadecimal
+                                    ("0", "x") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:0width$x}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+                                    // upper hexadecimal
+                                    ("0", "X") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:0width$X}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+
+                                    /*
+                                     * Alternate form
+                                     */
+                                    // octal
+                                    ("#", "o") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:>#width$o}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+                                    // lower hexadecimal
+                                    ("#", "x") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:>#width$x}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+                                    // upper hexadecimal
+                                    ("#", "X") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:>#width$X}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+
+                                    /*
+                                     * Left adjusted
+                                     */
+                                    // decimal
+                                    ("-", "d") | ("-", "i") | ("-", "u") => {
+                                        Box::new(move |n: usize| -> String {
+                                            format!(
+                                                "{}{}{:<#width$}{}",
+                                                prefix,
+                                                before,
+                                                n,
+                                                after,
+                                                width = n_digits
+                                            )
+                                        })
+                                    }
+                                    // octal
+                                    ("-", "o") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:<#width$o}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+                                    // lower hexadecimal
+                                    ("-", "x") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:<#width$x}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+                                    // upper hexadecimal
+                                    ("-", "X") => Box::new(move |n: usize| -> String {
+                                        format!(
+                                            "{}{}{:<#width$X}{}",
+                                            prefix,
+                                            before,
+                                            n,
+                                            after,
+                                            width = n_digits
+                                        )
+                                    }),
+
+                                    _ => return Err(CsplitError::SuffixFormatIncorrect),
+                                }
+                            }
+                            _ => return Err(CsplitError::SuffixFormatIncorrect),
+                        }
+                    }
+                    None => return Err(CsplitError::SuffixFormatIncorrect),
+                };
+
+                // there cannot be more than one format pattern
+                if captures_iter.next().is_some() {
+                    return Err(CsplitError::SuffixFormatTooManyPercents);
+                }
+                custom_fn
+            }
+        };
+
+        Ok(SplitName { fn_split_name })
+    }
+
+    /// Returns the filename of the i-th split.
+    pub fn get(&self, n: usize) -> String {
+        (self.fn_split_name)(n)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // spell-checker:ignore (path) xxcst
+
+    use super::*;
+
+    #[test]
+    fn invalid_number() {
+        let split_name = SplitName::new(None, None, Some(String::from("bad")));
+        match split_name {
+            Err(CsplitError::InvalidNumber(_)) => (),
+            _ => panic!("should fail with InvalidNumber"),
+        };
+    }
+
+    #[test]
+    fn invalid_suffix_format1() {
+        let split_name = SplitName::new(None, Some(String::from("no conversion string")), None);
+        match split_name {
+            Err(CsplitError::SuffixFormatIncorrect) => (),
+            _ => panic!("should fail with SuffixFormatIncorrect"),
+        };
+    }
+
+    #[test]
+    fn invalid_suffix_format2() {
+        let split_name = SplitName::new(None, Some(String::from("%042a")), None);
+        match split_name {
+            Err(CsplitError::SuffixFormatIncorrect) => (),
+            _ => panic!("should fail with SuffixFormatIncorrect"),
+        };
+    }
+
+    #[test]
+    fn default_formatter() {
+        let split_name = SplitName::new(None, None, None).unwrap();
+        assert_eq!(split_name.get(2), "xx02");
+    }
+
+    #[test]
+    fn default_formatter_with_prefix() {
+        let split_name = SplitName::new(Some(String::from("aaa")), None, None).unwrap();
+        assert_eq!(split_name.get(2), "aaa02");
+    }
+
+    #[test]
+    fn default_formatter_with_width() {
+        let split_name = SplitName::new(None, None, Some(String::from("5"))).unwrap();
+        assert_eq!(split_name.get(2), "xx00002");
+    }
+
+    #[test]
+    fn no_padding_decimal() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%d-")), None).unwrap();
+        assert_eq!(split_name.get(2), "xxcst-2-");
+    }
+
+    #[test]
+    fn zero_padding_decimal1() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%03d-")), None).unwrap();
+        assert_eq!(split_name.get(2), "xxcst-002-");
+    }
+
+    #[test]
+    fn zero_padding_decimal2() {
+        let split_name = SplitName::new(
+            Some(String::from("pre-")),
+            Some(String::from("cst-%03d-post")),
+            None,
+        )
+        .unwrap();
+        assert_eq!(split_name.get(2), "pre-cst-002-post");
+    }
+
+    #[test]
+    fn zero_padding_decimal3() {
+        let split_name = SplitName::new(
+            None,
+            Some(String::from("cst-%03d-")),
+            Some(String::from("42")),
+        )
+        .unwrap();
+        assert_eq!(split_name.get(2), "xxcst-002-");
+    }
+
+    #[test]
+    fn zero_padding_decimal4() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%03i-")), None).unwrap();
+        assert_eq!(split_name.get(2), "xxcst-002-");
+    }
+
+    #[test]
+    fn zero_padding_decimal5() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%03u-")), None).unwrap();
+        assert_eq!(split_name.get(2), "xxcst-002-");
+    }
+
+    #[test]
+    fn zero_padding_octal() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%03o-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-052-");
+    }
+
+    #[test]
+    fn zero_padding_lower_hex() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%03x-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-02a-");
+    }
+
+    #[test]
+    fn zero_padding_upper_hex() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%03X-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-02A-");
+    }
+
+    #[test]
+    fn alternate_form_octal() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%#10o-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-      0o52-");
+    }
+
+    #[test]
+    fn alternate_form_lower_hex() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%#10x-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-      0x2a-");
+    }
+
+    #[test]
+    fn alternate_form_upper_hex() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%#10X-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-      0x2A-");
+    }
+
+    #[test]
+    fn left_adjusted_decimal1() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%-10d-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-42        -");
+    }
+
+    #[test]
+    fn left_adjusted_decimal2() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%-10i-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-42        -");
+    }
+
+    #[test]
+    fn left_adjusted_decimal3() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%-10u-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-42        -");
+    }
+
+    #[test]
+    fn left_adjusted_octal() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%-10o-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-0o52      -");
+    }
+
+    #[test]
+    fn left_adjusted_lower_hex() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%-10x-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-0x2a      -");
+    }
+
+    #[test]
+    fn left_adjusted_upper_hex() {
+        let split_name = SplitName::new(None, Some(String::from("cst-%-10X-")), None).unwrap();
+        assert_eq!(split_name.get(42), "xxcst-0x2A      -");
+    }
+
+    #[test]
+    fn too_many_percent() {
+        let split_name = SplitName::new(None, Some(String::from("%02d-%-3x")), None);
+        match split_name {
+            Err(CsplitError::SuffixFormatTooManyPercents) => (),
+            _ => panic!("should fail with SuffixFormatTooManyPercents"),
+        };
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_cut/cut.rs.html b/src/uu_cut/cut.rs.html new file mode 100644 index 000000000..53bec4a6b --- /dev/null +++ b/src/uu_cut/cut.rs.html @@ -0,0 +1,1269 @@ +cut.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Rolf Morel <rolfmorel@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) delim sourcefiles
+
+#[macro_use]
+extern crate uucore;
+
+use bstr::io::BufReadExt;
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
+use std::path::Path;
+
+use self::searcher::Searcher;
+use uucore::ranges::Range;
+use uucore::InvalidEncodingHandling;
+
+mod searcher;
+
+static NAME: &str = "cut";
+static SYNTAX: &str =
+    "[-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+";
+static SUMMARY: &str =
+    "Prints specified byte or field columns from each line of stdin or the input files";
+static LONG_HELP: &str = "
+ Each call must specify a mode (what to use for columns),
+ a sequence (which columns to print), and provide a data source
+
+ Specifying a mode
+
+    Use --bytes (-b) or --characters (-c) to specify byte mode
+
+    Use --fields (-f) to specify field mode, where each line is broken into
+    fields identified by a delimiter character. For example for a typical CSV
+    you could use this in combination with setting comma as the delimiter
+
+ Specifying a sequence
+
+    A sequence is a group of 1 or more numbers or inclusive ranges separated
+    by a commas.
+
+    cut -f 2,5-7 some_file.txt
+    will display the 2nd, 5th, 6th, and 7th field for each source line
+
+    Ranges can extend to the end of the row by excluding the the second number
+
+    cut -f 3- some_file.txt
+    will display the 3rd field and all fields after for each source line
+
+    The first number of a range can be excluded, and this is effectively the
+    same as using 1 as the first number: it causes the range to begin at the
+    first column. Ranges can also display a single column
+
+    cut -f 1,3-5 some_file.txt
+    will display the 1st, 3rd, 4th, and 5th field for each source line
+
+    The --complement option, when used, inverts the effect of the sequence
+
+    cut --complement -f 4-6 some_file.txt
+    will display the every field but the 4th, 5th, and 6th
+
+ Specifying a data source
+
+    If no sourcefile arguments are specified, stdin is used as the source of
+    lines to print
+
+    If sourcefile arguments are specified, stdin is ignored and all files are
+    read in consecutively if a sourcefile is not successfully read, a warning
+    will print to stderr, and the eventual status code will be 1, but cut
+    will continue to read through proceeding sourcefiles
+
+    To print columns from both STDIN and a file argument, use - (dash) as a
+    sourcefile argument to represent stdin.
+
+ Field Mode options
+
+    The fields in each line are identified by a delimiter (separator)
+
+    Set the delimiter
+        Set the delimiter which separates fields in the file using the
+        --delimiter (-d) option. Setting the delimiter is optional.
+        If not set, a default delimiter of Tab will be used.
+
+    Optionally Filter based on delimiter
+        If the --only-delimited (-s) flag is provided, only lines which
+        contain the delimiter will be printed
+
+    Replace the delimiter
+        If the --output-delimiter option is provided, the argument used for
+        it will replace the delimiter character in each line printed. This is
+        useful for transforming tabular data - e.g. to convert a CSV to a
+        TSV (tab-separated file)
+
+ Line endings
+
+    When the --zero-terminated (-z) option is used, cut sees \\0 (null) as the
+    'line ending' character (both for the purposes of reading lines and
+    separating printed lines) instead of \\n (newline). This is useful for
+    tabular data where some of the cells may contain newlines
+
+    echo 'ab\\0cd' | cut -z -c 1
+    will result in 'a\\0c\\0'
+";
+
+struct Options {
+    out_delim: Option<String>,
+    zero_terminated: bool,
+}
+
+struct FieldOptions {
+    delimiter: String, // one char long, String because of UTF8 representation
+    out_delimiter: Option<String>,
+    only_delimited: bool,
+    zero_terminated: bool,
+}
+
+enum Mode {
+    Bytes(Vec<Range>, Options),
+    Characters(Vec<Range>, Options),
+    Fields(Vec<Range>, FieldOptions),
+}
+
+fn stdout_writer() -> Box<dyn Write> {
+    if atty::is(atty::Stream::Stdout) {
+        Box::new(stdout())
+    } else {
+        Box::new(BufWriter::new(stdout())) as Box<dyn Write>
+    }
+}
+
+fn list_to_ranges(list: &str, complement: bool) -> Result<Vec<Range>, String> {
+    if complement {
+        Range::from_list(list).map(|r| uucore::ranges::complement(&r))
+    } else {
+        Range::from_list(list)
+    }
+}
+
+fn cut_bytes<R: Read>(reader: R, ranges: &[Range], opts: &Options) -> i32 {
+    let newline_char = if opts.zero_terminated { b'\0' } else { b'\n' };
+    let buf_in = BufReader::new(reader);
+    let mut out = stdout_writer();
+    let delim = opts
+        .out_delim
+        .as_ref()
+        .map_or("", String::as_str)
+        .as_bytes();
+
+    let res = buf_in.for_byte_record(newline_char, |line| {
+        let mut print_delim = false;
+        for &Range { low, high } in ranges {
+            if low > line.len() {
+                break;
+            }
+            if print_delim {
+                out.write_all(delim)?;
+            } else if opts.out_delim.is_some() {
+                print_delim = true;
+            }
+            // change `low` from 1-indexed value to 0-index value
+            let low = low - 1;
+            let high = high.min(line.len());
+            out.write_all(&line[low..high])?;
+        }
+        out.write_all(&[newline_char])?;
+        Ok(true)
+    });
+    crash_if_err!(1, res);
+    0
+}
+
+#[allow(clippy::cognitive_complexity)]
+fn cut_fields_delimiter<R: Read>(
+    reader: R,
+    ranges: &[Range],
+    delim: &str,
+    only_delimited: bool,
+    newline_char: u8,
+    out_delim: &str,
+) -> i32 {
+    let buf_in = BufReader::new(reader);
+    let mut out = stdout_writer();
+    let input_delim_len = delim.len();
+
+    let result = buf_in.for_byte_record_with_terminator(newline_char, |line| {
+        let mut fields_pos = 1;
+        let mut low_idx = 0;
+        let mut delim_search = Searcher::new(line, delim.as_bytes()).peekable();
+        let mut print_delim = false;
+
+        if delim_search.peek().is_none() {
+            if !only_delimited {
+                out.write_all(line)?;
+                if line[line.len() - 1] != newline_char {
+                    out.write_all(&[newline_char])?;
+                }
+            }
+
+            return Ok(true);
+        }
+
+        for &Range { low, high } in ranges {
+            if low - fields_pos > 0 {
+                low_idx = match delim_search.nth(low - fields_pos - 1) {
+                    Some(index) => index + input_delim_len,
+                    None => break,
+                };
+            }
+
+            for _ in 0..=high - low {
+                if print_delim {
+                    out.write_all(out_delim.as_bytes())?;
+                } else {
+                    print_delim = true;
+                }
+
+                match delim_search.next() {
+                    Some(high_idx) => {
+                        let segment = &line[low_idx..high_idx];
+
+                        out.write_all(segment)?;
+
+                        low_idx = high_idx + input_delim_len;
+                        fields_pos = high + 1;
+                    }
+                    None => {
+                        let segment = &line[low_idx..];
+
+                        out.write_all(segment)?;
+
+                        if line[line.len() - 1] == newline_char {
+                            return Ok(true);
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+
+        out.write_all(&[newline_char])?;
+        Ok(true)
+    });
+    crash_if_err!(1, result);
+    0
+}
+
+#[allow(clippy::cognitive_complexity)]
+fn cut_fields<R: Read>(reader: R, ranges: &[Range], opts: &FieldOptions) -> i32 {
+    let newline_char = if opts.zero_terminated { b'\0' } else { b'\n' };
+    if let Some(ref o_delim) = opts.out_delimiter {
+        return cut_fields_delimiter(
+            reader,
+            ranges,
+            &opts.delimiter,
+            opts.only_delimited,
+            newline_char,
+            o_delim,
+        );
+    }
+
+    let buf_in = BufReader::new(reader);
+    let mut out = stdout_writer();
+    let delim_len = opts.delimiter.len();
+
+    let result = buf_in.for_byte_record_with_terminator(newline_char, |line| {
+        let mut fields_pos = 1;
+        let mut low_idx = 0;
+        let mut delim_search = Searcher::new(line, opts.delimiter.as_bytes()).peekable();
+        let mut print_delim = false;
+
+        if delim_search.peek().is_none() {
+            if !opts.only_delimited {
+                out.write_all(line)?;
+                if line[line.len() - 1] != newline_char {
+                    out.write_all(&[newline_char])?;
+                }
+            }
+
+            return Ok(true);
+        }
+
+        for &Range { low, high } in ranges {
+            if low - fields_pos > 0 {
+                if let Some(delim_pos) = delim_search.nth(low - fields_pos - 1) {
+                    low_idx = if print_delim {
+                        delim_pos
+                    } else {
+                        delim_pos + delim_len
+                    }
+                } else {
+                    break;
+                }
+            }
+
+            match delim_search.nth(high - low) {
+                Some(high_idx) => {
+                    let segment = &line[low_idx..high_idx];
+
+                    out.write_all(segment)?;
+
+                    print_delim = true;
+                    low_idx = high_idx;
+                    fields_pos = high + 1;
+                }
+                None => {
+                    let segment = &line[low_idx..line.len()];
+
+                    out.write_all(segment)?;
+
+                    if line[line.len() - 1] == newline_char {
+                        return Ok(true);
+                    }
+                    break;
+                }
+            }
+        }
+        out.write_all(&[newline_char])?;
+        Ok(true)
+    });
+    crash_if_err!(1, result);
+    0
+}
+
+fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
+    let mut stdin_read = false;
+    let mut exit_code = 0;
+
+    if filenames.is_empty() {
+        filenames.push("-".to_owned());
+    }
+
+    for filename in &filenames {
+        if filename == "-" {
+            if stdin_read {
+                continue;
+            }
+
+            exit_code |= match mode {
+                Mode::Bytes(ref ranges, ref opts) => cut_bytes(stdin(), ranges, opts),
+                Mode::Characters(ref ranges, ref opts) => cut_bytes(stdin(), ranges, opts),
+                Mode::Fields(ref ranges, ref opts) => cut_fields(stdin(), ranges, opts),
+            };
+
+            stdin_read = true;
+        } else {
+            let path = Path::new(&filename[..]);
+
+            if path.is_dir() {
+                show_error!("{}: Is a directory", filename);
+                continue;
+            }
+
+            if path.metadata().is_err() {
+                show_error!("{}: No such file or directory", filename);
+                continue;
+            }
+
+            let file = match File::open(&path) {
+                Ok(f) => f,
+                Err(e) => {
+                    show_error!("opening '{}': {}", &filename[..], e);
+                    continue;
+                }
+            };
+
+            exit_code |= match mode {
+                Mode::Bytes(ref ranges, ref opts) => cut_bytes(file, ranges, opts),
+                Mode::Characters(ref ranges, ref opts) => cut_bytes(file, ranges, opts),
+                Mode::Fields(ref ranges, ref opts) => cut_fields(file, ranges, opts),
+            };
+        }
+    }
+
+    exit_code
+}
+
+mod options {
+    pub const BYTES: &str = "bytes";
+    pub const CHARACTERS: &str = "characters";
+    pub const DELIMITER: &str = "delimiter";
+    pub const FIELDS: &str = "fields";
+    pub const ZERO_TERMINATED: &str = "zero-terminated";
+    pub const ONLY_DELIMITED: &str = "only-delimited";
+    pub const OUTPUT_DELIMITER: &str = "output-delimiter";
+    pub const COMPLEMENT: &str = "complement";
+    pub const FILE: &str = "file";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let complement = matches.is_present(options::COMPLEMENT);
+
+    let mode_parse = match (
+        matches.value_of(options::BYTES),
+        matches.value_of(options::CHARACTERS),
+        matches.value_of(options::FIELDS),
+    ) {
+        (Some(byte_ranges), None, None) => list_to_ranges(byte_ranges, complement).map(|ranges| {
+            Mode::Bytes(
+                ranges,
+                Options {
+                    out_delim: Some(
+                        matches
+                            .value_of(options::OUTPUT_DELIMITER)
+                            .unwrap_or_default()
+                            .to_owned(),
+                    ),
+                    zero_terminated: matches.is_present(options::ZERO_TERMINATED),
+                },
+            )
+        }),
+        (None, Some(char_ranges), None) => list_to_ranges(char_ranges, complement).map(|ranges| {
+            Mode::Characters(
+                ranges,
+                Options {
+                    out_delim: Some(
+                        matches
+                            .value_of(options::OUTPUT_DELIMITER)
+                            .unwrap_or_default()
+                            .to_owned(),
+                    ),
+                    zero_terminated: matches.is_present(options::ZERO_TERMINATED),
+                },
+            )
+        }),
+        (None, None, Some(field_ranges)) => {
+            list_to_ranges(field_ranges, complement).and_then(|ranges| {
+                let out_delim = match matches.value_of(options::OUTPUT_DELIMITER) {
+                    Some(s) => {
+                        if s.is_empty() {
+                            Some("\0".to_owned())
+                        } else {
+                            Some(s.to_owned())
+                        }
+                    }
+                    None => None,
+                };
+
+                let only_delimited = matches.is_present(options::ONLY_DELIMITED);
+                let zero_terminated = matches.is_present(options::ZERO_TERMINATED);
+
+                match matches.value_of(options::DELIMITER) {
+                    Some(mut delim) => {
+                        // GNU's `cut` supports `-d=` to set the delimiter to `=`.
+                        // Clap parsing is limited in this situation, see:
+                        // https://github.com/uutils/coreutils/issues/2424#issuecomment-863825242
+                        // Since clap parsing handles `-d=` as delimiter explicitly set to "" and
+                        // an empty delimiter is not accepted by GNU's `cut` (and makes no sense),
+                        // we can use this as basis for a simple workaround:
+                        if delim.is_empty() {
+                            delim = "=";
+                        }
+                        if delim.chars().count() > 1 {
+                            Err(msg_opt_invalid_should_be!(
+                                "empty or 1 character long",
+                                "a value 2 characters or longer",
+                                "--delimiter",
+                                "-d"
+                            ))
+                        } else {
+                            let delim = if delim.is_empty() {
+                                "\0".to_owned()
+                            } else {
+                                delim.to_owned()
+                            };
+
+                            Ok(Mode::Fields(
+                                ranges,
+                                FieldOptions {
+                                    delimiter: delim,
+                                    out_delimiter: out_delim,
+                                    only_delimited,
+                                    zero_terminated,
+                                },
+                            ))
+                        }
+                    }
+                    None => Ok(Mode::Fields(
+                        ranges,
+                        FieldOptions {
+                            delimiter: "\t".to_owned(),
+                            out_delimiter: out_delim,
+                            only_delimited,
+                            zero_terminated,
+                        },
+                    )),
+                }
+            })
+        }
+        (ref b, ref c, ref f) if b.is_some() || c.is_some() || f.is_some() => Err(
+            msg_expects_no_more_than_one_of!("--fields (-f)", "--chars (-c)", "--bytes (-b)"),
+        ),
+        _ => Err(msg_expects_one_of!(
+            "--fields (-f)",
+            "--chars (-c)",
+            "--bytes (-b)"
+        )),
+    };
+
+    let mode_parse = match mode_parse {
+        Err(_) => mode_parse,
+        Ok(mode) => match mode {
+            Mode::Bytes(_, _) | Mode::Characters(_, _)
+                if matches.is_present(options::DELIMITER) =>
+            {
+                Err(msg_opt_only_usable_if!(
+                    "printing a sequence of fields",
+                    "--delimiter",
+                    "-d"
+                ))
+            }
+            Mode::Bytes(_, _) | Mode::Characters(_, _)
+                if matches.is_present(options::ONLY_DELIMITED) =>
+            {
+                Err(msg_opt_only_usable_if!(
+                    "printing a sequence of fields",
+                    "--only-delimited",
+                    "-s"
+                ))
+            }
+            _ => Ok(mode),
+        },
+    };
+
+    let files: Vec<String> = matches
+        .values_of(options::FILE)
+        .unwrap_or_default()
+        .map(str::to_owned)
+        .collect();
+
+    match mode_parse {
+        Ok(mode) => cut_files(files, mode),
+        Err(err_msg) => {
+            show_error!("{}", err_msg);
+            1
+        }
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(SYNTAX)
+        .about(SUMMARY)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::BYTES)
+                .short("b")
+                .long(options::BYTES)
+                .takes_value(true)
+                .help("filter byte columns from the input source")
+                .allow_hyphen_values(true)
+                .value_name("LIST")
+                .display_order(1),
+        )
+        .arg(
+            Arg::with_name(options::CHARACTERS)
+                .short("c")
+                .long(options::CHARACTERS)
+                .help("alias for character mode")
+                .takes_value(true)
+                .allow_hyphen_values(true)
+                .value_name("LIST")
+                .display_order(2),
+        )
+        .arg(
+            Arg::with_name(options::DELIMITER)
+                .short("d")
+                .long(options::DELIMITER)
+                .help("specify the delimiter character that separates fields in the input source. Defaults to Tab.")
+                .takes_value(true)
+                .value_name("DELIM")
+                .display_order(3),
+        )
+        .arg(
+            Arg::with_name(options::FIELDS)
+                .short("f")
+                .long(options::FIELDS)
+                .help("filter field columns from the input source")
+                .takes_value(true)
+                .allow_hyphen_values(true)
+                .value_name("LIST")
+                .display_order(4),
+        )
+        .arg(
+            Arg::with_name(options::COMPLEMENT)
+                .long(options::COMPLEMENT)
+                .help("invert the filter - instead of displaying only the filtered columns, display all but those columns")
+                .takes_value(false)
+                .display_order(5),
+        )
+        .arg(
+            Arg::with_name(options::ONLY_DELIMITED)
+            .short("s")
+                .long(options::ONLY_DELIMITED)
+                .help("in field mode, only print lines which contain the delimiter")
+                .takes_value(false)
+                .display_order(6),
+        )
+        .arg(
+            Arg::with_name(options::ZERO_TERMINATED)
+            .short("z")
+                .long(options::ZERO_TERMINATED)
+                .help("instead of filtering columns based on line, filter columns based on \\0 (NULL character)")
+                .takes_value(false)
+                .display_order(8),
+        )
+        .arg(
+            Arg::with_name(options::OUTPUT_DELIMITER)
+            .long(options::OUTPUT_DELIMITER)
+                .help("in field mode, replace the delimiter in output lines with this option's argument")
+                .takes_value(true)
+                .value_name("NEW_DELIM")
+                .display_order(7),
+        )
+        .arg(
+            Arg::with_name(options::FILE)
+            .hidden(true)
+                .multiple(true)
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_cut/searcher.rs.html b/src/uu_cut/searcher.rs.html new file mode 100644 index 000000000..f634abc46 --- /dev/null +++ b/src/uu_cut/searcher.rs.html @@ -0,0 +1,215 @@ +searcher.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Rolf Morel <rolfmorel@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use memchr::memchr;
+
+pub struct Searcher<'a> {
+    haystack: &'a [u8],
+    needle: &'a [u8],
+    position: usize,
+}
+
+impl<'a> Searcher<'a> {
+    pub fn new(haystack: &'a [u8], needle: &'a [u8]) -> Searcher<'a> {
+        assert!(!needle.is_empty());
+        Searcher {
+            haystack,
+            needle,
+            position: 0,
+        }
+    }
+}
+
+impl<'a> Iterator for Searcher<'a> {
+    type Item = usize;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        loop {
+            if let Some(match_idx) = memchr(self.needle[0], self.haystack) {
+                if self.needle.len() == 1
+                    || self.haystack[match_idx + 1..].starts_with(&self.needle[1..])
+                {
+                    let match_pos = self.position + match_idx;
+                    let skip = match_idx + self.needle.len();
+                    self.haystack = &self.haystack[skip..];
+                    self.position += skip;
+                    return Some(match_pos);
+                } else {
+                    let skip = match_idx + 1;
+                    self.haystack = &self.haystack[skip..];
+                    self.position += skip;
+                    // continue
+                }
+            } else {
+                return None;
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    const NEEDLE: &[u8] = "ab".as_bytes();
+
+    #[test]
+    fn test_normal() {
+        let iter = Searcher::new("a.a.a".as_bytes(), "a".as_bytes());
+        let items: Vec<usize> = iter.collect();
+        assert_eq!(vec![0, 2, 4], items);
+    }
+
+    #[test]
+    fn test_empty() {
+        let iter = Searcher::new("".as_bytes(), "a".as_bytes());
+        let items: Vec<usize> = iter.collect();
+        assert_eq!(vec![] as Vec<usize>, items);
+    }
+
+    fn test_multibyte(line: &[u8], expected: Vec<usize>) {
+        let iter = Searcher::new(line, NEEDLE);
+        let items: Vec<usize> = iter.collect();
+        assert_eq!(expected, items);
+    }
+
+    #[test]
+    fn test_multibyte_normal() {
+        test_multibyte("...ab...ab...".as_bytes(), vec![3, 8]);
+    }
+
+    #[test]
+    fn test_multibyte_needle_head_at_end() {
+        test_multibyte("a".as_bytes(), vec![]);
+    }
+
+    #[test]
+    fn test_multibyte_starting_needle() {
+        test_multibyte("ab...ab...".as_bytes(), vec![0, 5]);
+    }
+
+    #[test]
+    fn test_multibyte_trailing_needle() {
+        test_multibyte("...ab...ab".as_bytes(), vec![3, 8]);
+    }
+
+    #[test]
+    fn test_multibyte_first_byte_false_match() {
+        test_multibyte("aA..aCaC..ab..aD".as_bytes(), vec![10]);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_date/date.rs.html b/src/uu_date/date.rs.html new file mode 100644 index 000000000..ad2e09a7a --- /dev/null +++ b/src/uu_date/date.rs.html @@ -0,0 +1,837 @@ +date.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Anthony Deschamps <anthony.j.deschamps@gmail.com>
+// (c) Sylvestre Ledru <sylvestre@debian.org>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (chrono) Datelike Timelike ; (format) DATEFILE MMDDhhmm ; (vars) datetime datetimes
+
+use chrono::{DateTime, FixedOffset, Local, Offset, Utc};
+#[cfg(windows)]
+use chrono::{Datelike, Timelike};
+use clap::{crate_version, App, Arg};
+#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))]
+use libc::{clock_settime, timespec, CLOCK_REALTIME};
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+use std::path::PathBuf;
+#[cfg(windows)]
+use winapi::{
+    shared::minwindef::WORD,
+    um::{minwinbase::SYSTEMTIME, sysinfoapi::SetSystemTime},
+};
+
+// Options
+const DATE: &str = "date";
+const HOURS: &str = "hours";
+const MINUTES: &str = "minutes";
+const SECONDS: &str = "seconds";
+const HOUR: &str = "hour";
+const MINUTE: &str = "minute";
+const SECOND: &str = "second";
+const NS: &str = "ns";
+
+const NAME: &str = "date";
+const ABOUT: &str = "print or set the system date and time";
+
+const OPT_DATE: &str = "date";
+const OPT_FORMAT: &str = "format";
+const OPT_FILE: &str = "file";
+const OPT_DEBUG: &str = "debug";
+const OPT_ISO_8601: &str = "iso-8601";
+const OPT_RFC_EMAIL: &str = "rfc-email";
+const OPT_RFC_3339: &str = "rfc-3339";
+const OPT_SET: &str = "set";
+const OPT_REFERENCE: &str = "reference";
+const OPT_UNIVERSAL: &str = "universal";
+const OPT_UNIVERSAL_2: &str = "utc";
+
+// Help strings
+
+static ISO_8601_HELP_STRING: &str = "output date/time in ISO 8601 format.
+ FMT='date' for date only (the default),
+ 'hours', 'minutes', 'seconds', or 'ns'
+ for date and time to the indicated precision.
+ Example: 2006-08-14T02:34:56-06:00";
+
+static RFC_5322_HELP_STRING: &str = "output date and time in RFC 5322 format.
+ Example: Mon, 14 Aug 2006 02:34:56 -0600";
+
+static RFC_3339_HELP_STRING: &str = "output date/time in RFC 3339 format.
+ FMT='date', 'seconds', or 'ns'
+ for date and time to the indicated precision.
+ Example: 2006-08-14 02:34:56-06:00";
+
+#[cfg(not(any(target_os = "macos", target_os = "redox")))]
+static OPT_SET_HELP_STRING: &str = "set time described by STRING";
+#[cfg(target_os = "macos")]
+static OPT_SET_HELP_STRING: &str = "set time described by STRING (not available on mac yet)";
+#[cfg(target_os = "redox")]
+static OPT_SET_HELP_STRING: &str = "set time described by STRING (not available on redox yet)";
+
+/// Settings for this program, parsed from the command line
+struct Settings {
+    utc: bool,
+    format: Format,
+    date_source: DateSource,
+    set_to: Option<DateTime<FixedOffset>>,
+}
+
+/// Various ways of displaying the date
+enum Format {
+    Iso8601(Iso8601Format),
+    Rfc5322,
+    Rfc3339(Rfc3339Format),
+    Custom(String),
+    Default,
+}
+
+/// Various places that dates can come from
+enum DateSource {
+    Now,
+    Custom(String),
+    File(PathBuf),
+}
+
+enum Iso8601Format {
+    Date,
+    Hours,
+    Minutes,
+    Seconds,
+    Ns,
+}
+
+impl<'a> From<&'a str> for Iso8601Format {
+    fn from(s: &str) -> Self {
+        match s {
+            HOURS | HOUR => Iso8601Format::Hours,
+            MINUTES | MINUTE => Iso8601Format::Minutes,
+            SECONDS | SECOND => Iso8601Format::Seconds,
+            NS => Iso8601Format::Ns,
+            DATE => Iso8601Format::Date,
+            // Should be caught by clap
+            _ => panic!("Invalid format: {}", s),
+        }
+    }
+}
+
+enum Rfc3339Format {
+    Date,
+    Seconds,
+    Ns,
+}
+
+impl<'a> From<&'a str> for Rfc3339Format {
+    fn from(s: &str) -> Self {
+        match s {
+            DATE => Rfc3339Format::Date,
+            SECONDS | SECOND => Rfc3339Format::Seconds,
+            NS => Rfc3339Format::Ns,
+            // Should be caught by clap
+            _ => panic!("Invalid format: {}", s),
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let syntax = format!(
+        "{0} [OPTION]... [+FORMAT]...
+ {0} [OPTION]... [MMDDhhmm[[CC]YY][.ss]]",
+        NAME
+    );
+    let matches = uu_app().usage(&syntax[..]).get_matches_from(args);
+
+    let format = if let Some(form) = matches.value_of(OPT_FORMAT) {
+        if !form.starts_with('+') {
+            eprintln!("date: invalid date '{}'", form);
+            return 1;
+        }
+        let form = form[1..].to_string();
+        Format::Custom(form)
+    } else if let Some(fmt) = matches
+        .values_of(OPT_ISO_8601)
+        .map(|mut iter| iter.next().unwrap_or(DATE).into())
+    {
+        Format::Iso8601(fmt)
+    } else if matches.is_present(OPT_RFC_EMAIL) {
+        Format::Rfc5322
+    } else if let Some(fmt) = matches.value_of(OPT_RFC_3339).map(Into::into) {
+        Format::Rfc3339(fmt)
+    } else {
+        Format::Default
+    };
+
+    let date_source = if let Some(date) = matches.value_of(OPT_DATE) {
+        DateSource::Custom(date.into())
+    } else if let Some(file) = matches.value_of(OPT_FILE) {
+        DateSource::File(file.into())
+    } else {
+        DateSource::Now
+    };
+
+    let set_to = match matches.value_of(OPT_SET).map(parse_date) {
+        None => None,
+        Some(Err((input, _err))) => {
+            eprintln!("date: invalid date '{}'", input);
+            return 1;
+        }
+        Some(Ok(date)) => Some(date),
+    };
+
+    let settings = Settings {
+        utc: matches.is_present(OPT_UNIVERSAL),
+        format,
+        date_source,
+        set_to,
+    };
+
+    if let Some(date) = settings.set_to {
+        // All set time functions expect UTC datetimes.
+        let date: DateTime<Utc> = if settings.utc {
+            date.with_timezone(&Utc)
+        } else {
+            date.into()
+        };
+
+        return set_system_datetime(date);
+    } else {
+        // Declare a file here because it needs to outlive the `dates` iterator.
+        let file: File;
+
+        // Get the current time, either in the local time zone or UTC.
+        let now: DateTime<FixedOffset> = if settings.utc {
+            let now = Utc::now();
+            now.with_timezone(&now.offset().fix())
+        } else {
+            let now = Local::now();
+            now.with_timezone(now.offset())
+        };
+
+        // Iterate over all dates - whether it's a single date or a file.
+        let dates: Box<dyn Iterator<Item = _>> = match settings.date_source {
+            DateSource::Custom(ref input) => {
+                let date = parse_date(input.clone());
+                let iter = std::iter::once(date);
+                Box::new(iter)
+            }
+            DateSource::File(ref path) => {
+                file = File::open(path).unwrap();
+                let lines = BufReader::new(file).lines();
+                let iter = lines.filter_map(Result::ok).map(parse_date);
+                Box::new(iter)
+            }
+            DateSource::Now => {
+                let iter = std::iter::once(Ok(now));
+                Box::new(iter)
+            }
+        };
+
+        let format_string = make_format_string(&settings);
+
+        // Format all the dates
+        for date in dates {
+            match date {
+                Ok(date) => {
+                    // GNU `date` uses `%N` for nano seconds, however crate::chrono uses `%f`
+                    let format_string = &format_string.replace("%N", "%f");
+                    let formatted = date.format(format_string).to_string().replace("%f", "%N");
+                    println!("{}", formatted);
+                }
+                Err((input, _err)) => {
+                    println!("date: invalid date '{}'", input);
+                }
+            }
+        }
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_DATE)
+                .short("d")
+                .long(OPT_DATE)
+                .takes_value(true)
+                .help("display time described by STRING, not 'now'"),
+        )
+        .arg(
+            Arg::with_name(OPT_FILE)
+                .short("f")
+                .long(OPT_FILE)
+                .takes_value(true)
+                .help("like --date; once for each line of DATEFILE"),
+        )
+        .arg(
+            Arg::with_name(OPT_ISO_8601)
+                .short("I")
+                .long(OPT_ISO_8601)
+                .takes_value(true)
+                .help(ISO_8601_HELP_STRING),
+        )
+        .arg(
+            Arg::with_name(OPT_RFC_EMAIL)
+                .short("R")
+                .long(OPT_RFC_EMAIL)
+                .help(RFC_5322_HELP_STRING),
+        )
+        .arg(
+            Arg::with_name(OPT_RFC_3339)
+                .long(OPT_RFC_3339)
+                .takes_value(true)
+                .help(RFC_3339_HELP_STRING),
+        )
+        .arg(
+            Arg::with_name(OPT_DEBUG)
+                .long(OPT_DEBUG)
+                .help("annotate the parsed date, and warn about questionable usage to stderr"),
+        )
+        .arg(
+            Arg::with_name(OPT_REFERENCE)
+                .short("r")
+                .long(OPT_REFERENCE)
+                .takes_value(true)
+                .help("display the last modification time of FILE"),
+        )
+        .arg(
+            Arg::with_name(OPT_SET)
+                .short("s")
+                .long(OPT_SET)
+                .takes_value(true)
+                .help(OPT_SET_HELP_STRING),
+        )
+        .arg(
+            Arg::with_name(OPT_UNIVERSAL)
+                .short("u")
+                .long(OPT_UNIVERSAL)
+                .alias(OPT_UNIVERSAL_2)
+                .help("print or set Coordinated Universal Time (UTC)"),
+        )
+        .arg(Arg::with_name(OPT_FORMAT).multiple(false))
+}
+
+/// Return the appropriate format string for the given settings.
+fn make_format_string(settings: &Settings) -> &str {
+    match settings.format {
+        Format::Iso8601(ref fmt) => match *fmt {
+            Iso8601Format::Date => "%F",
+            Iso8601Format::Hours => "%FT%H%:z",
+            Iso8601Format::Minutes => "%FT%H:%M%:z",
+            Iso8601Format::Seconds => "%FT%T%:z",
+            Iso8601Format::Ns => "%FT%T,%f%:z",
+        },
+        Format::Rfc5322 => "%a, %d %h %Y %T %z",
+        Format::Rfc3339(ref fmt) => match *fmt {
+            Rfc3339Format::Date => "%F",
+            Rfc3339Format::Seconds => "%F %T%:z",
+            Rfc3339Format::Ns => "%F %T.%f%:z",
+        },
+        Format::Custom(ref fmt) => fmt,
+        Format::Default => "%c",
+    }
+}
+
+/// Parse a `String` into a `DateTime`.
+/// If it fails, return a tuple of the `String` along with its `ParseError`.
+fn parse_date<S: AsRef<str> + Clone>(
+    s: S,
+) -> Result<DateTime<FixedOffset>, (String, chrono::format::ParseError)> {
+    // TODO: The GNU date command can parse a wide variety of inputs.
+    s.as_ref().parse().map_err(|e| (s.as_ref().into(), e))
+}
+
+#[cfg(not(any(unix, windows)))]
+fn set_system_datetime(_date: DateTime<Utc>) -> i32 {
+    unimplemented!("setting date not implemented (unsupported target)");
+}
+
+#[cfg(target_os = "macos")]
+fn set_system_datetime(_date: DateTime<Utc>) -> i32 {
+    eprintln!("date: setting the date is not supported by macOS");
+    1
+}
+
+#[cfg(target_os = "redox")]
+fn set_system_datetime(_date: DateTime<Utc>) -> i32 {
+    eprintln!("date: setting the date is not supported by Redox");
+    1
+}
+
+#[cfg(all(unix, not(target_os = "macos"), not(target_os = "redox")))]
+/// System call to set date (unix).
+/// See here for more:
+/// https://doc.rust-lang.org/libc/i686-unknown-linux-gnu/libc/fn.clock_settime.html
+/// https://linux.die.net/man/3/clock_settime
+/// https://www.gnu.org/software/libc/manual/html_node/Time-Types.html
+fn set_system_datetime(date: DateTime<Utc>) -> i32 {
+    let timespec = timespec {
+        tv_sec: date.timestamp() as _,
+        tv_nsec: date.timestamp_subsec_nanos() as _,
+    };
+
+    let result = unsafe { clock_settime(CLOCK_REALTIME, &timespec) };
+
+    if result != 0 {
+        let error = std::io::Error::last_os_error();
+        eprintln!("date: cannot set date: {}", error);
+        error.raw_os_error().unwrap()
+    } else {
+        0
+    }
+}
+
+#[cfg(windows)]
+/// System call to set date (Windows).
+/// See here for more:
+/// https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-setsystemtime
+/// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-systemtime
+fn set_system_datetime(date: DateTime<Utc>) -> i32 {
+    let system_time = SYSTEMTIME {
+        wYear: date.year() as WORD,
+        wMonth: date.month() as WORD,
+        // Ignored
+        wDayOfWeek: 0,
+        wDay: date.day() as WORD,
+        wHour: date.hour() as WORD,
+        wMinute: date.minute() as WORD,
+        wSecond: date.second() as WORD,
+        // TODO: be careful of leap seconds - valid range is [0, 999] - how to handle?
+        wMilliseconds: ((date.nanosecond() / 1_000_000) % 1000) as WORD,
+    };
+
+    let result = unsafe { SetSystemTime(&system_time) };
+
+    if result == 0 {
+        let error = std::io::Error::last_os_error();
+        eprintln!("date: cannot set date: {}", error);
+        error.raw_os_error().unwrap()
+    } else {
+        0
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_dd/conversion_tables.rs.html b/src/uu_dd/conversion_tables.rs.html new file mode 100644 index 000000000..54f59af1a --- /dev/null +++ b/src/uu_dd/conversion_tables.rs.html @@ -0,0 +1,447 @@ +conversion_tables.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Tyler Steele <tyler.steele@protonmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// Note: Conversion tables are just lookup tables.
+// eg. The ASCII->EBCDIC table stores the EBCDIC code at the index
+// obtained by treating the ASCII representation as a number.
+
+pub type ConversionTable = [u8; 256];
+
+pub const ASCII_UCASE_TO_LCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+    0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_LCASE_TO_UCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+    0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_TO_EBCDIC: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0x5f, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x6a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0x4a, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xa1, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_TO_EBCDIC_UCASE_TO_LCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0x5f, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x6a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0x4a, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xa1, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_TO_EBCDIC_LCASE_TO_UCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x9a, 0x6d,
+    0x79, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xc0, 0x4f, 0xd0, 0x5f, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x6a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0x4a, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xa1, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_TO_IBM: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_TO_IBM_UCASE_TO_LCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const ASCII_TO_IBM_LCASE_TO_UCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
+    0x79, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const EBCDIC_TO_ASCII: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x9c, 0x09, 0x86, 0x7f, 0x97, 0x8d, 0x8e, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x9d, 0x85, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8f, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x0a, 0x17, 0x1b, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x05, 0x06, 0x07,
+    0x90, 0x91, 0x16, 0x93, 0x94, 0x95, 0x96, 0x04, 0x98, 0x99, 0x9a, 0x9b, 0x14, 0x15, 0x9e, 0x1a,
+    0x20, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xd5, 0x2e, 0x3c, 0x28, 0x2b, 0x7c,
+    0x26, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0x21, 0x24, 0x2a, 0x29, 0x3b, 0x7e,
+    0x2d, 0x2f, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xcb, 0x2c, 0x25, 0x5f, 0x3e, 0x3f,
+    0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0x60, 0x3a, 0x23, 0x40, 0x27, 0x3d, 0x22,
+    0xc3, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
+    0xca, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x5e, 0xcc, 0xcd, 0xce, 0xcf, 0xd0,
+    0xd1, 0xe5, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0xd2, 0xd3, 0xd4, 0x5b, 0xd6, 0xd7,
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0x5d, 0xe6, 0xe7,
+    0x7b, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed,
+    0x7d, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
+    0x5c, 0x9f, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const EBCDIC_TO_ASCII_UCASE_TO_LCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
+    0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
+    0x97, 0x98, 0x99, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+pub const EBCDIC_TO_ASCII_LCASE_TO_UCASE: ConversionTable = [
+    0x00, 0x01, 0x02, 0x03, 0x37, 0x2d, 0x2e, 0x2f, 0x16, 0x05, 0x25, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+    0x10, 0x11, 0x12, 0x13, 0x3c, 0x3d, 0x32, 0x26, 0x18, 0x19, 0x3f, 0x27, 0x1c, 0x1d, 0x1e, 0x1f,
+    0x40, 0x5a, 0x7f, 0x7b, 0x5b, 0x6c, 0x50, 0x7d, 0x4d, 0x5d, 0x5c, 0x4e, 0x6b, 0x60, 0x4b, 0x61,
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0x7a, 0x5e, 0x4c, 0x7e, 0x6e, 0x6f,
+    0x7c, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xad, 0xe0, 0xbd, 0x5f, 0x6d,
+    0x79, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,
+    0xd7, 0xd8, 0xd9, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xc0, 0x4f, 0xd0, 0xa1, 0x07,
+    0x20, 0x21, 0x22, 0x23, 0x24, 0x15, 0x06, 0x17, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x09, 0x0a, 0x1b,
+    0x30, 0x31, 0x1a, 0x33, 0x34, 0x35, 0x36, 0x08, 0x38, 0x39, 0x3a, 0x3b, 0x04, 0x14, 0x3e, 0xe1,
+    0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+    0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x80, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e,
+    0x9f, 0xa0, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xda, 0xdb,
+    0xdc, 0xdd, 0xde, 0xdf, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+];
+
+
\ No newline at end of file diff --git a/src/uu_dd/datastructures.rs.html b/src/uu_dd/datastructures.rs.html new file mode 100644 index 000000000..186d81f99 --- /dev/null +++ b/src/uu_dd/datastructures.rs.html @@ -0,0 +1,349 @@ +datastructures.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Tyler Steele <tyler.steele@protonmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+// spell-checker:ignore ctable, outfile
+
+use crate::conversion_tables::*;
+
+use std::error::Error;
+use std::time;
+
+pub struct ProgUpdate {
+    pub read_stat: ReadStat,
+    pub write_stat: WriteStat,
+    pub duration: time::Duration,
+}
+
+#[derive(Clone, Copy, Default)]
+pub struct ReadStat {
+    pub reads_complete: u64,
+    pub reads_partial: u64,
+    pub records_truncated: u32,
+}
+impl std::ops::AddAssign for ReadStat {
+    fn add_assign(&mut self, other: Self) {
+        *self = Self {
+            reads_complete: self.reads_complete + other.reads_complete,
+            reads_partial: self.reads_partial + other.reads_partial,
+            records_truncated: self.records_truncated + other.records_truncated,
+        }
+    }
+}
+
+#[derive(Clone, Copy)]
+pub struct WriteStat {
+    pub writes_complete: u64,
+    pub writes_partial: u64,
+    pub bytes_total: u128,
+}
+impl std::ops::AddAssign for WriteStat {
+    fn add_assign(&mut self, other: Self) {
+        *self = Self {
+            writes_complete: self.writes_complete + other.writes_complete,
+            writes_partial: self.writes_partial + other.writes_partial,
+            bytes_total: self.bytes_total + other.bytes_total,
+        }
+    }
+}
+
+type Cbs = usize;
+
+/// Stores all Conv Flags that apply to the input
+#[derive(Debug, Default, PartialEq)]
+pub struct IConvFlags {
+    pub ctable: Option<&'static ConversionTable>,
+    pub block: Option<Cbs>,
+    pub unblock: Option<Cbs>,
+    pub swab: bool,
+    pub sync: Option<u8>,
+    pub noerror: bool,
+}
+
+/// Stores all Conv Flags that apply to the output
+#[derive(Debug, Default, PartialEq)]
+pub struct OConvFlags {
+    pub sparse: bool,
+    pub excl: bool,
+    pub nocreat: bool,
+    pub notrunc: bool,
+    pub fdatasync: bool,
+    pub fsync: bool,
+}
+
+/// Stores all Flags that apply to the input
+#[derive(Debug, Default, PartialEq)]
+pub struct IFlags {
+    pub cio: bool,
+    pub direct: bool,
+    pub directory: bool,
+    pub dsync: bool,
+    pub sync: bool,
+    pub nocache: bool,
+    pub nonblock: bool,
+    pub noatime: bool,
+    pub noctty: bool,
+    pub nofollow: bool,
+    pub nolinks: bool,
+    pub binary: bool,
+    pub text: bool,
+    pub fullblock: bool,
+    pub count_bytes: bool,
+    pub skip_bytes: bool,
+}
+
+/// Stores all Flags that apply to the output
+#[derive(Debug, Default, PartialEq)]
+pub struct OFlags {
+    pub append: bool,
+    pub cio: bool,
+    pub direct: bool,
+    pub directory: bool,
+    pub dsync: bool,
+    pub sync: bool,
+    pub nocache: bool,
+    pub nonblock: bool,
+    pub noatime: bool,
+    pub noctty: bool,
+    pub nofollow: bool,
+    pub nolinks: bool,
+    pub binary: bool,
+    pub text: bool,
+    pub seek_bytes: bool,
+}
+
+/// The value of the status cl-option.
+/// Controls printing of transfer stats
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum StatusLevel {
+    Progress,
+    Noxfer,
+    None,
+}
+
+/// The value of count=N
+/// Defaults to Reads(N)
+/// if iflag=count_bytes
+/// then becomes Bytes(N)
+#[derive(Debug, PartialEq)]
+pub enum CountType {
+    Reads(usize),
+    Bytes(usize),
+}
+
+#[derive(Debug)]
+pub enum InternalError {
+    WrongInputType,
+    WrongOutputType,
+    InvalidConvBlockUnblockCase,
+}
+
+impl std::fmt::Display for InternalError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::WrongInputType | Self::WrongOutputType => {
+                write!(f, "Internal dd error: Wrong Input/Output data type")
+            }
+            Self::InvalidConvBlockUnblockCase => {
+                write!(f, "Invalid Conversion, Block, or Unblock data")
+            }
+        }
+    }
+}
+
+impl Error for InternalError {}
+
+pub mod options {
+    pub const INFILE: &str = "if";
+    pub const OUTFILE: &str = "of";
+    pub const IBS: &str = "ibs";
+    pub const OBS: &str = "obs";
+    pub const BS: &str = "bs";
+    pub const CBS: &str = "cbs";
+    pub const COUNT: &str = "count";
+    pub const SKIP: &str = "skip";
+    pub const SEEK: &str = "seek";
+    pub const STATUS: &str = "status";
+    pub const CONV: &str = "conv";
+    pub const IFLAG: &str = "iflag";
+    pub const OFLAG: &str = "oflag";
+}
+
+
\ No newline at end of file diff --git a/src/uu_dd/dd.rs.html b/src/uu_dd/dd.rs.html new file mode 100644 index 000000000..57c99adcd --- /dev/null +++ b/src/uu_dd/dd.rs.html @@ -0,0 +1,2293 @@ +dd.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Tyler Steele <tyler.steele@protonmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, btotal, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, sigval, wlen, wstat
+
+use uucore::InvalidEncodingHandling;
+
+#[cfg(test)]
+mod dd_unit_tests;
+
+mod datastructures;
+use datastructures::*;
+
+mod parseargs;
+use parseargs::Matches;
+
+mod conversion_tables;
+use conversion_tables::*;
+
+use byte_unit::Byte;
+use clap::{self, crate_version};
+use gcd::Gcd;
+#[cfg(target_os = "linux")]
+use signal_hook::consts::signal;
+use std::cmp;
+use std::convert::TryInto;
+use std::env;
+use std::error::Error;
+use std::fs::{File, OpenOptions};
+use std::io::{self, Read, Seek, Write};
+#[cfg(target_os = "linux")]
+use std::os::unix::fs::OpenOptionsExt;
+use std::path::Path;
+use std::sync::mpsc;
+#[cfg(target_os = "linux")]
+use std::sync::{atomic::AtomicUsize, atomic::Ordering, Arc};
+use std::thread;
+use std::time;
+
+const ABOUT: &str = "copy, and optionally convert, a file system resource";
+const BUF_INIT_BYTE: u8 = 0xDD;
+const RTN_SUCCESS: i32 = 0;
+const RTN_FAILURE: i32 = 1;
+const NEWLINE: u8 = b'\n';
+const SPACE: u8 = b' ';
+
+struct Input<R: Read> {
+    src: R,
+    non_ascii: bool,
+    ibs: usize,
+    print_level: Option<StatusLevel>,
+    count: Option<CountType>,
+    cflags: IConvFlags,
+    iflags: IFlags,
+}
+
+impl Input<io::Stdin> {
+    fn new(matches: &Matches) -> Result<Self, Box<dyn Error>> {
+        let ibs = parseargs::parse_ibs(matches)?;
+        let non_ascii = parseargs::parse_input_non_ascii(matches)?;
+        let print_level = parseargs::parse_status_level(matches)?;
+        let cflags = parseargs::parse_conv_flag_input(matches)?;
+        let iflags = parseargs::parse_iflags(matches)?;
+        let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
+        let count = parseargs::parse_count(&iflags, matches)?;
+
+        let mut i = Input {
+            src: io::stdin(),
+            non_ascii,
+            ibs,
+            print_level,
+            count,
+            cflags,
+            iflags,
+        };
+
+        if let Some(amt) = skip {
+            let mut buf = vec![BUF_INIT_BYTE; amt];
+
+            i.force_fill(&mut buf, amt)?;
+        }
+
+        Ok(i)
+    }
+}
+
+#[cfg(target_os = "linux")]
+fn make_linux_iflags(iflags: &IFlags) -> Option<libc::c_int> {
+    let mut flag = 0;
+
+    if iflags.direct {
+        flag |= libc::O_DIRECT;
+    }
+    if iflags.directory {
+        flag |= libc::O_DIRECTORY;
+    }
+    if iflags.dsync {
+        flag |= libc::O_DSYNC;
+    }
+    if iflags.noatime {
+        flag |= libc::O_NOATIME;
+    }
+    if iflags.noctty {
+        flag |= libc::O_NOCTTY;
+    }
+    if iflags.nofollow {
+        flag |= libc::O_NOFOLLOW;
+    }
+    if iflags.nonblock {
+        flag |= libc::O_NONBLOCK;
+    }
+    if iflags.sync {
+        flag |= libc::O_SYNC;
+    }
+
+    if flag != 0 {
+        Some(flag)
+    } else {
+        None
+    }
+}
+
+impl Input<File> {
+    fn new(matches: &Matches) -> Result<Self, Box<dyn Error>> {
+        let ibs = parseargs::parse_ibs(matches)?;
+        let non_ascii = parseargs::parse_input_non_ascii(matches)?;
+        let print_level = parseargs::parse_status_level(matches)?;
+        let cflags = parseargs::parse_conv_flag_input(matches)?;
+        let iflags = parseargs::parse_iflags(matches)?;
+        let skip = parseargs::parse_skip_amt(&ibs, &iflags, matches)?;
+        let count = parseargs::parse_count(&iflags, matches)?;
+
+        if let Some(fname) = matches.value_of(options::INFILE) {
+            let mut src = {
+                let mut opts = OpenOptions::new();
+                opts.read(true);
+
+                #[cfg(target_os = "linux")]
+                if let Some(libc_flags) = make_linux_iflags(&iflags) {
+                    opts.custom_flags(libc_flags);
+                }
+
+                opts.open(fname)?
+            };
+
+            if let Some(amt) = skip {
+                let amt: u64 = amt.try_into()?;
+                src.seek(io::SeekFrom::Start(amt))?;
+            }
+
+            let i = Input {
+                src,
+                non_ascii,
+                ibs,
+                print_level,
+                count,
+                cflags,
+                iflags,
+            };
+
+            Ok(i)
+        } else {
+            Err(Box::new(InternalError::WrongInputType))
+        }
+    }
+}
+
+impl<R: Read> Read for Input<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut base_idx = 0;
+        let target_len = buf.len();
+        loop {
+            match self.src.read(&mut buf[base_idx..]) {
+                Ok(0) => return Ok(base_idx),
+                Ok(rlen) if self.iflags.fullblock => {
+                    base_idx += rlen;
+
+                    if base_idx >= target_len {
+                        return Ok(target_len);
+                    }
+                }
+                Ok(len) => return Ok(len),
+                Err(e) if e.kind() == io::ErrorKind::Interrupted => continue,
+                Err(_) if self.cflags.noerror => return Ok(base_idx),
+                Err(e) => return Err(e),
+            }
+        }
+    }
+}
+
+impl<R: Read> Input<R> {
+    /// Fills a given buffer.
+    /// Reads in increments of 'self.ibs'.
+    /// The start of each ibs-sized read follows the previous one.
+    fn fill_consecutive(&mut self, buf: &mut Vec<u8>) -> Result<ReadStat, Box<dyn Error>> {
+        let mut reads_complete = 0;
+        let mut reads_partial = 0;
+        let mut bytes_total = 0;
+
+        for chunk in buf.chunks_mut(self.ibs) {
+            match self.read(chunk)? {
+                rlen if rlen == self.ibs => {
+                    bytes_total += rlen;
+                    reads_complete += 1;
+                }
+                rlen if rlen > 0 => {
+                    bytes_total += rlen;
+                    reads_partial += 1;
+                }
+                _ => break,
+            }
+        }
+
+        buf.truncate(bytes_total);
+        Ok(ReadStat {
+            reads_complete,
+            reads_partial,
+            // Records are not truncated when filling.
+            records_truncated: 0,
+        })
+    }
+
+    /// Fills a given buffer.
+    /// Reads in increments of 'self.ibs'.
+    /// The start of each ibs-sized read is aligned to multiples of ibs; remaining space is filled with the 'pad' byte.
+    fn fill_blocks(&mut self, buf: &mut Vec<u8>, pad: u8) -> Result<ReadStat, Box<dyn Error>> {
+        let mut reads_complete = 0;
+        let mut reads_partial = 0;
+        let mut base_idx = 0;
+
+        while base_idx < buf.len() {
+            let next_blk = cmp::min(base_idx + self.ibs, buf.len());
+            let target_len = next_blk - base_idx;
+
+            match self.read(&mut buf[base_idx..next_blk])? {
+                0 => break,
+                rlen if rlen < target_len => {
+                    reads_partial += 1;
+                    let padding = vec![pad; target_len - rlen];
+                    buf.splice(base_idx + rlen..next_blk, padding.into_iter());
+                }
+                _ => {
+                    reads_complete += 1;
+                }
+            }
+
+            base_idx += self.ibs;
+        }
+
+        buf.truncate(base_idx);
+        Ok(ReadStat {
+            reads_complete,
+            reads_partial,
+            records_truncated: 0,
+        })
+    }
+
+    /// Force-fills a buffer, ignoring zero-length reads which would otherwise be
+    /// interpreted as EOF.
+    /// Note: This will not return unless the source (eventually) produces
+    /// enough bytes to meet target_len.
+    fn force_fill(&mut self, buf: &mut [u8], target_len: usize) -> Result<usize, Box<dyn Error>> {
+        let mut base_idx = 0;
+        while base_idx < target_len {
+            base_idx += self.read(&mut buf[base_idx..target_len])?;
+        }
+
+        Ok(base_idx)
+    }
+}
+
+trait OutputTrait: Sized + Write {
+    fn new(matches: &Matches) -> Result<Self, Box<dyn Error>>;
+    fn fsync(&mut self) -> io::Result<()>;
+    fn fdatasync(&mut self) -> io::Result<()>;
+}
+
+struct Output<W: Write> {
+    dst: W,
+    obs: usize,
+    cflags: OConvFlags,
+}
+
+impl OutputTrait for Output<io::Stdout> {
+    fn new(matches: &Matches) -> Result<Self, Box<dyn Error>> {
+        let obs = parseargs::parse_obs(matches)?;
+        let cflags = parseargs::parse_conv_flag_output(matches)?;
+
+        let dst = io::stdout();
+
+        Ok(Output { dst, obs, cflags })
+    }
+
+    fn fsync(&mut self) -> io::Result<()> {
+        self.dst.flush()
+    }
+
+    fn fdatasync(&mut self) -> io::Result<()> {
+        self.dst.flush()
+    }
+}
+
+impl<W: Write> Output<W>
+where
+    Self: OutputTrait,
+{
+    fn write_blocks(&mut self, buf: Vec<u8>) -> io::Result<WriteStat> {
+        let mut writes_complete = 0;
+        let mut writes_partial = 0;
+        let mut bytes_total = 0;
+
+        for chunk in buf.chunks(self.obs) {
+            match self.write(chunk)? {
+                wlen if wlen < chunk.len() => {
+                    writes_partial += 1;
+                    bytes_total += wlen;
+                }
+                wlen => {
+                    writes_complete += 1;
+                    bytes_total += wlen;
+                }
+            }
+        }
+
+        Ok(WriteStat {
+            writes_complete,
+            writes_partial,
+            bytes_total: bytes_total.try_into().unwrap_or(0u128),
+        })
+    }
+
+    fn dd_out<R: Read>(mut self, mut i: Input<R>) -> Result<(), Box<dyn Error>> {
+        let mut rstat = ReadStat {
+            reads_complete: 0,
+            reads_partial: 0,
+            records_truncated: 0,
+        };
+        let mut wstat = WriteStat {
+            writes_complete: 0,
+            writes_partial: 0,
+            bytes_total: 0,
+        };
+        let start = time::Instant::now();
+        let bsize = calc_bsize(i.ibs, self.obs);
+
+        let prog_tx = {
+            let (tx, rx) = mpsc::channel();
+            thread::spawn(gen_prog_updater(rx, i.print_level));
+            tx
+        };
+
+        while below_count_limit(&i.count, &rstat, &wstat) {
+            // Read/Write
+            let loop_bsize = calc_loop_bsize(&i.count, &rstat, &wstat, i.ibs, bsize);
+            match read_helper(&mut i, loop_bsize)? {
+                (
+                    ReadStat {
+                        reads_complete: 0,
+                        reads_partial: 0,
+                        ..
+                    },
+                    _,
+                ) => break,
+                (rstat_update, buf) => {
+                    let wstat_update = self.write_blocks(buf)?;
+
+                    rstat += rstat_update;
+                    wstat += wstat_update;
+                }
+            };
+            // Update Prog
+            prog_tx.send(ProgUpdate {
+                read_stat: rstat,
+                write_stat: wstat,
+                duration: start.elapsed(),
+            })?;
+        }
+
+        if self.cflags.fsync {
+            self.fsync()?;
+        } else if self.cflags.fdatasync {
+            self.fdatasync()?;
+        }
+
+        match i.print_level {
+            Some(StatusLevel::Noxfer) | Some(StatusLevel::None) => {}
+            _ => print_transfer_stats(&ProgUpdate {
+                read_stat: rstat,
+                write_stat: wstat,
+                duration: start.elapsed(),
+            }),
+        }
+        Ok(())
+    }
+}
+
+#[cfg(target_os = "linux")]
+fn make_linux_oflags(oflags: &OFlags) -> Option<libc::c_int> {
+    let mut flag = 0;
+
+    // oflag=FLAG
+    if oflags.append {
+        flag |= libc::O_APPEND;
+    }
+    if oflags.direct {
+        flag |= libc::O_DIRECT;
+    }
+    if oflags.directory {
+        flag |= libc::O_DIRECTORY;
+    }
+    if oflags.dsync {
+        flag |= libc::O_DSYNC;
+    }
+    if oflags.noatime {
+        flag |= libc::O_NOATIME;
+    }
+    if oflags.noctty {
+        flag |= libc::O_NOCTTY;
+    }
+    if oflags.nofollow {
+        flag |= libc::O_NOFOLLOW;
+    }
+    if oflags.nonblock {
+        flag |= libc::O_NONBLOCK;
+    }
+    if oflags.sync {
+        flag |= libc::O_SYNC;
+    }
+
+    if flag != 0 {
+        Some(flag)
+    } else {
+        None
+    }
+}
+
+impl OutputTrait for Output<File> {
+    fn new(matches: &Matches) -> Result<Self, Box<dyn Error>> {
+        fn open_dst(path: &Path, cflags: &OConvFlags, oflags: &OFlags) -> Result<File, io::Error> {
+            let mut opts = OpenOptions::new();
+            opts.write(true)
+                .create(!cflags.nocreat)
+                .truncate(!cflags.notrunc)
+                .create_new(cflags.excl)
+                .append(oflags.append);
+
+            #[cfg(target_os = "linux")]
+            if let Some(libc_flags) = make_linux_oflags(oflags) {
+                opts.custom_flags(libc_flags);
+            }
+
+            opts.open(path)
+        }
+        let obs = parseargs::parse_obs(matches)?;
+        let cflags = parseargs::parse_conv_flag_output(matches)?;
+        let oflags = parseargs::parse_oflags(matches)?;
+        let seek = parseargs::parse_seek_amt(&obs, &oflags, matches)?;
+
+        if let Some(fname) = matches.value_of(options::OUTFILE) {
+            let mut dst = open_dst(Path::new(&fname), &cflags, &oflags)?;
+
+            if let Some(amt) = seek {
+                let amt: u64 = amt.try_into()?;
+                dst.seek(io::SeekFrom::Start(amt))?;
+            }
+
+            Ok(Output { dst, obs, cflags })
+        } else {
+            // The following error should only occur if someone
+            // mistakenly calls Output::<File>::new() without checking
+            // if 'of' has been provided. In this case,
+            // Output::<io::stdout>::new() is probably intended.
+            Err(Box::new(InternalError::WrongOutputType))
+        }
+    }
+
+    fn fsync(&mut self) -> io::Result<()> {
+        self.dst.flush()?;
+        self.dst.sync_all()
+    }
+
+    fn fdatasync(&mut self) -> io::Result<()> {
+        self.dst.flush()?;
+        self.dst.sync_data()
+    }
+}
+
+impl Seek for Output<File> {
+    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
+        self.dst.seek(pos)
+    }
+}
+
+impl Write for Output<File> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        fn is_sparse(buf: &[u8]) -> bool {
+            buf.iter().all(|&e| e == 0u8)
+        }
+        // -----------------------------
+        if self.cflags.sparse && is_sparse(buf) {
+            let seek_amt: i64 = buf
+                .len()
+                .try_into()
+                .expect("Internal dd Error: Seek amount greater than signed 64-bit integer");
+            self.dst.seek(io::SeekFrom::Current(seek_amt))?;
+            Ok(buf.len())
+        } else {
+            self.dst.write(buf)
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.dst.flush()
+    }
+}
+
+impl Write for Output<io::Stdout> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.dst.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.dst.flush()
+    }
+}
+
+/// Splits the content of buf into cbs-length blocks
+/// Appends padding as specified by conv=block and cbs=N
+/// Expects ascii encoded data
+fn block(buf: Vec<u8>, cbs: usize, rstat: &mut ReadStat) -> Vec<Vec<u8>> {
+    let mut blocks = buf
+        .split(|&e| e == NEWLINE)
+        .map(|split| split.to_vec())
+        .fold(Vec::new(), |mut blocks, mut split| {
+            if split.len() > cbs {
+                rstat.records_truncated += 1;
+            }
+            split.resize(cbs, SPACE);
+            blocks.push(split);
+
+            blocks
+        });
+
+    if let Some(last) = blocks.last() {
+        if last.iter().all(|&e| e == SPACE) {
+            blocks.pop();
+        }
+    }
+
+    blocks
+}
+
+/// Trims padding from each cbs-length partition of buf
+/// as specified by conv=unblock and cbs=N
+/// Expects ascii encoded data
+fn unblock(buf: Vec<u8>, cbs: usize) -> Vec<u8> {
+    buf.chunks(cbs).fold(Vec::new(), |mut acc, block| {
+        if let Some(last_char_idx) = block.iter().rposition(|&e| e != SPACE) {
+            // Include text up to last space.
+            acc.extend(&block[..=last_char_idx]);
+        }
+
+        acc.push(NEWLINE);
+        acc
+    })
+}
+
+/// A helper for teasing out which options must be applied and in which order.
+/// Some user options, such as the presence of conversion tables, will determine whether the input is assumed to be ascii. The parser sets the Input::non_ascii flag accordingly.
+/// Examples:
+///     - If conv=ebcdic or conv=ibm is specified then block, unblock or swab must be performed before the conversion happens since the source will start in ascii.
+///     - If conv=ascii is specified then block, unblock or swab must be performed after the conversion since the source starts in ebcdic.
+///     - If no conversion is specified then the source is assumed to be in ascii.
+/// For more info see `info dd`
+fn conv_block_unblock_helper<R: Read>(
+    mut buf: Vec<u8>,
+    i: &mut Input<R>,
+    rstat: &mut ReadStat,
+) -> Result<Vec<u8>, Box<dyn Error>> {
+    // Local Predicate Fns -------------------------------------------------
+    fn should_block_then_conv<R: Read>(i: &Input<R>) -> bool {
+        !i.non_ascii && i.cflags.block.is_some()
+    }
+    fn should_conv_then_block<R: Read>(i: &Input<R>) -> bool {
+        i.non_ascii && i.cflags.block.is_some()
+    }
+    fn should_unblock_then_conv<R: Read>(i: &Input<R>) -> bool {
+        !i.non_ascii && i.cflags.unblock.is_some()
+    }
+    fn should_conv_then_unblock<R: Read>(i: &Input<R>) -> bool {
+        i.non_ascii && i.cflags.unblock.is_some()
+    }
+    fn conv_only<R: Read>(i: &Input<R>) -> bool {
+        i.cflags.ctable.is_some() && i.cflags.block.is_none() && i.cflags.unblock.is_none()
+    }
+    // Local Helper Fns ----------------------------------------------------
+    fn apply_conversion(buf: &mut [u8], ct: &ConversionTable) {
+        for idx in 0..buf.len() {
+            buf[idx] = ct[buf[idx] as usize];
+        }
+    }
+    // --------------------------------------------------------------------
+    if conv_only(i) {
+        // no block/unblock
+        let ct = i.cflags.ctable.unwrap();
+        apply_conversion(&mut buf, ct);
+
+        Ok(buf)
+    } else if should_block_then_conv(i) {
+        // ascii input so perform the block first
+        let cbs = i.cflags.block.unwrap();
+
+        let mut blocks = block(buf, cbs, rstat);
+
+        if let Some(ct) = i.cflags.ctable {
+            for buf in blocks.iter_mut() {
+                apply_conversion(buf, ct);
+            }
+        }
+
+        let blocks = blocks.into_iter().flatten().collect();
+
+        Ok(blocks)
+    } else if should_conv_then_block(i) {
+        // Non-ascii so perform the conversion first
+        let cbs = i.cflags.block.unwrap();
+
+        if let Some(ct) = i.cflags.ctable {
+            apply_conversion(&mut buf, ct);
+        }
+
+        let blocks = block(buf, cbs, rstat).into_iter().flatten().collect();
+
+        Ok(blocks)
+    } else if should_unblock_then_conv(i) {
+        // ascii input so perform the unblock first
+        let cbs = i.cflags.unblock.unwrap();
+
+        let mut buf = unblock(buf, cbs);
+
+        if let Some(ct) = i.cflags.ctable {
+            apply_conversion(&mut buf, ct);
+        }
+
+        Ok(buf)
+    } else if should_conv_then_unblock(i) {
+        // Non-ascii input so perform the conversion first
+        let cbs = i.cflags.unblock.unwrap();
+
+        if let Some(ct) = i.cflags.ctable {
+            apply_conversion(&mut buf, ct);
+        }
+
+        let buf = unblock(buf, cbs);
+
+        Ok(buf)
+    } else {
+        // The following error should not happen, as it results from
+        // insufficient command line data. This case should be caught
+        // by the parser before making it this far.
+        // Producing this error is an alternative to risking an unwrap call
+        // on 'cbs' if the required data is not provided.
+        Err(Box::new(InternalError::InvalidConvBlockUnblockCase))
+    }
+}
+
+/// Read helper performs read operations common to all dd reads, and dispatches the buffer to relevant helper functions as dictated by the operations requested by the user.
+fn read_helper<R: Read>(
+    i: &mut Input<R>,
+    bsize: usize,
+) -> Result<(ReadStat, Vec<u8>), Box<dyn Error>> {
+    // Local Predicate Fns -----------------------------------------------
+    fn is_conv<R: Read>(i: &Input<R>) -> bool {
+        i.cflags.ctable.is_some()
+    }
+    fn is_block<R: Read>(i: &Input<R>) -> bool {
+        i.cflags.block.is_some()
+    }
+    fn is_unblock<R: Read>(i: &Input<R>) -> bool {
+        i.cflags.unblock.is_some()
+    }
+    // Local Helper Fns -------------------------------------------------
+    fn perform_swab(buf: &mut [u8]) {
+        for base in (1..buf.len()).step_by(2) {
+            buf.swap(base, base - 1);
+        }
+    }
+    // ------------------------------------------------------------------
+    // Read
+    let mut buf = vec![BUF_INIT_BYTE; bsize];
+    let mut rstat = match i.cflags.sync {
+        Some(ch) => i.fill_blocks(&mut buf, ch)?,
+        _ => i.fill_consecutive(&mut buf)?,
+    };
+    // Return early if no data
+    if rstat.reads_complete == 0 && rstat.reads_partial == 0 {
+        return Ok((rstat, buf));
+    }
+
+    // Perform any conv=x[,x...] options
+    if i.cflags.swab {
+        perform_swab(&mut buf);
+    }
+    if is_conv(i) || is_block(i) || is_unblock(i) {
+        let buf = conv_block_unblock_helper(buf, i, &mut rstat)?;
+        Ok((rstat, buf))
+    } else {
+        Ok((rstat, buf))
+    }
+}
+
+// Print io lines of a status update:
+// <complete>+<partial> records in
+// <complete>+<partial> records out
+fn print_io_lines(update: &ProgUpdate) {
+    eprintln!(
+        "{}+{} records in",
+        update.read_stat.reads_complete, update.read_stat.reads_partial
+    );
+    if update.read_stat.records_truncated > 0 {
+        eprintln!("{} truncated records", update.read_stat.records_truncated);
+    }
+    eprintln!(
+        "{}+{} records out",
+        update.write_stat.writes_complete, update.write_stat.writes_partial
+    );
+}
+// Print the progress line of a status update:
+// <byte-count> bytes (<base-1000-size>, <base-2-size>) copied, <time> s, <base-2-rate>/s
+fn make_prog_line(update: &ProgUpdate) -> String {
+    let btotal_metric = Byte::from_bytes(update.write_stat.bytes_total)
+        .get_appropriate_unit(false)
+        .format(0);
+    let btotal_bin = Byte::from_bytes(update.write_stat.bytes_total)
+        .get_appropriate_unit(true)
+        .format(0);
+    let safe_millis = cmp::max(1, update.duration.as_millis());
+    let transfer_rate = Byte::from_bytes(1000 * (update.write_stat.bytes_total / safe_millis))
+        .get_appropriate_unit(false)
+        .format(1);
+
+    format!(
+        "{} bytes ({}, {}) copied, {:.1} s, {}/s",
+        update.write_stat.bytes_total,
+        btotal_metric,
+        btotal_bin,
+        update.duration.as_secs_f64(),
+        transfer_rate
+    )
+}
+// Print progress line only. Overwrite the current line.
+fn reprint_prog_line(update: &ProgUpdate) {
+    eprint!("\r{}", make_prog_line(update));
+}
+// Print progress line only. Print as a new line.
+fn print_prog_line(update: &ProgUpdate) {
+    eprintln!("{}", make_prog_line(update));
+}
+// Print both io lines and progress line.
+fn print_transfer_stats(update: &ProgUpdate) {
+    print_io_lines(update);
+    print_prog_line(update);
+}
+
+// Generate a progress updater that tracks progress, receives updates, and responds to progress update requests (signals).
+// Signals:
+// - SIGUSR1: Trigger progress line reprint. Linux (GNU & BSD) only.
+// - TODO: SIGINFO: Trigger progress line reprint. BSD-style Linux only.
+fn gen_prog_updater(rx: mpsc::Receiver<ProgUpdate>, print_level: Option<StatusLevel>) -> impl Fn() {
+    // --------------------------------------------------------------
+    #[cfg(target_os = "linux")]
+    const SIGUSR1_USIZE: usize = signal::SIGUSR1 as usize;
+    // --------------------------------------------------------------
+    #[cfg(target_os = "linux")]
+    fn posixly_correct() -> bool {
+        env::var("POSIXLY_CORRECT").is_ok()
+    }
+    #[cfg(target_os = "linux")]
+    fn register_linux_signal_handler(sigval: Arc<AtomicUsize>) -> Result<(), Box<dyn Error>> {
+        if !posixly_correct() {
+            signal_hook::flag::register_usize(signal::SIGUSR1, sigval, SIGUSR1_USIZE)?;
+        }
+
+        Ok(())
+    }
+    // --------------------------------------------------------------
+    move || {
+        #[cfg(target_os = "linux")]
+        let sigval = Arc::new(AtomicUsize::new(0));
+
+        #[cfg(target_os = "linux")]
+        register_linux_signal_handler(sigval.clone()).unwrap_or_else(|e| {
+            if Some(StatusLevel::None) != print_level {
+                eprintln!(
+                    "Internal dd Warning: Unable to register signal handler \n\t{}",
+                    e
+                );
+            }
+        });
+
+        while let Ok(update) = rx.recv() {
+            // (Re)print status line if progress is requested.
+            if Some(StatusLevel::Progress) == print_level {
+                reprint_prog_line(&update);
+            }
+            // Handle signals
+            #[cfg(target_os = "linux")]
+            if let SIGUSR1_USIZE = sigval.load(Ordering::Relaxed) {
+                print_transfer_stats(&update);
+            };
+        }
+    }
+}
+
+// Calculate a 'good' internal buffer size.
+// For performance of the read/write functions, the buffer should hold
+// both an integral number of reads and an integral number of writes. For
+// sane real-world memory use, it should not be too large. I believe
+// the least common multiple is a good representation of these interests.
+// https://en.wikipedia.org/wiki/Least_common_multiple#Using_the_greatest_common_divisor
+fn calc_bsize(ibs: usize, obs: usize) -> usize {
+    let gcd = Gcd::gcd(ibs, obs);
+    // calculate the lcm from gcd
+    (ibs / gcd) * obs
+}
+
+// Calculate the buffer size appropriate for this loop iteration, respecting
+// a count=N if present.
+fn calc_loop_bsize(
+    count: &Option<CountType>,
+    rstat: &ReadStat,
+    wstat: &WriteStat,
+    ibs: usize,
+    ideal_bsize: usize,
+) -> usize {
+    match count {
+        Some(CountType::Reads(rmax)) => {
+            let rmax: u64 = (*rmax).try_into().unwrap();
+            let rsofar = rstat.reads_complete + rstat.reads_partial;
+            let rremain: usize = (rmax - rsofar).try_into().unwrap();
+            cmp::min(ideal_bsize, rremain * ibs)
+        }
+        Some(CountType::Bytes(bmax)) => {
+            let bmax: u128 = (*bmax).try_into().unwrap();
+            let bremain: usize = (bmax - wstat.bytes_total).try_into().unwrap();
+            cmp::min(ideal_bsize, bremain)
+        }
+        None => ideal_bsize,
+    }
+}
+
+// Decide if the current progress is below a count=N limit or return
+// true if no such limit is set.
+fn below_count_limit(count: &Option<CountType>, rstat: &ReadStat, wstat: &WriteStat) -> bool {
+    match count {
+        Some(CountType::Reads(n)) => {
+            let n = (*n).try_into().unwrap();
+            rstat.reads_complete + rstat.reads_partial <= n
+        }
+        Some(CountType::Bytes(n)) => {
+            let n = (*n).try_into().unwrap();
+            wstat.bytes_total <= n
+        }
+        None => true,
+    }
+}
+
+fn append_dashes_if_not_present(mut acc: Vec<String>, mut s: String) -> Vec<String> {
+    if !s.starts_with("--") && !s.starts_with('-') {
+        s.insert_str(0, "--");
+    }
+    acc.push(s);
+    acc
+}
+
+macro_rules! unpack_or_rtn (
+    ($i:expr, $o:expr) =>
+    {{
+        match ($i, $o)
+        {
+            (Ok(i), Ok(o)) =>
+                (i,o),
+            (Err(e), _) =>
+            {
+                eprintln!("dd Error: {}", e);
+                return RTN_FAILURE;
+            },
+            (_, Err(e)) =>
+            {
+                eprintln!("dd Error: {}", e);
+                return RTN_FAILURE;
+            },
+        }
+    }};
+);
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let dashed_args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any()
+        .into_iter()
+        .fold(Vec::new(), append_dashes_if_not_present);
+
+    let matches = uu_app()
+        //.after_help(TODO: Add note about multiplier strings here.)
+        .get_matches_from(dashed_args);
+
+    let result = match (
+        matches.is_present(options::INFILE),
+        matches.is_present(options::OUTFILE),
+    ) {
+        (true, true) => {
+            let (i, o) =
+                unpack_or_rtn!(Input::<File>::new(&matches), Output::<File>::new(&matches));
+
+            o.dd_out(i)
+        }
+        (false, true) => {
+            let (i, o) = unpack_or_rtn!(
+                Input::<io::Stdin>::new(&matches),
+                Output::<File>::new(&matches)
+            );
+
+            o.dd_out(i)
+        }
+        (true, false) => {
+            let (i, o) = unpack_or_rtn!(
+                Input::<File>::new(&matches),
+                Output::<io::Stdout>::new(&matches)
+            );
+
+            o.dd_out(i)
+        }
+        (false, false) => {
+            let (i, o) = unpack_or_rtn!(
+                Input::<io::Stdin>::new(&matches),
+                Output::<io::Stdout>::new(&matches)
+            );
+
+            o.dd_out(i)
+        }
+    };
+    match result {
+        Ok(_) => RTN_SUCCESS,
+        Err(e) => {
+            eprintln!("dd exiting with error:\n\t{}", e);
+            RTN_FAILURE
+        }
+    }
+}
+
+pub fn uu_app() -> clap::App<'static, 'static> {
+    clap::App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            clap::Arg::with_name(options::INFILE)
+                .long(options::INFILE)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("FILE")
+                .help("(alternatively if=FILE) specifies the file used for input. When not specified, stdin is used instead")
+        )
+        .arg(
+            clap::Arg::with_name(options::OUTFILE)
+                .long(options::OUTFILE)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("FILE")
+                .help("(alternatively of=FILE) specifies the file used for output. When not specified, stdout is used instead")
+        )
+        .arg(
+            clap::Arg::with_name(options::IBS)
+                .long(options::IBS)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively ibs=N) specifies the size of buffer used for reads (default: 512). Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::OBS)
+                .long(options::OBS)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively obs=N) specifies the size of buffer used for writes (default: 512). Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::BS)
+                .long(options::BS)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively bs=N) specifies ibs=N and obs=N (default: 512). If ibs or obs are also specified, bs=N takes precedence. Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::CBS)
+                .long(options::CBS)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively cbs=BYTES) specifies the 'conversion block size' in bytes. Applies to the conv=block, and conv=unblock operations. Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::SKIP)
+                .long(options::SKIP)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively skip=N) causes N ibs-sized records of input to be skipped before beginning copy/convert operations. See iflag=count_bytes if skipping N bytes is preferred. Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::SEEK)
+                .long(options::SEEK)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively seek=N) seeks N obs-sized records into output before beginning copy/convert operations. See oflag=seek_bytes if seeking N bytes is preferred. Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::COUNT)
+                .long(options::COUNT)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("N")
+                .help("(alternatively count=N) stop reading input after N ibs-sized read operations rather than proceeding until EOF. See iflag=count_bytes if stopping after N bytes is preferred. Multiplier strings permitted.")
+        )
+        .arg(
+            clap::Arg::with_name(options::STATUS)
+                .long(options::STATUS)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("LEVEL")
+                .help("(alternatively status=LEVEL) controls whether volume and performance stats are written to stderr.
+
+When unspecified, dd will print stats upon completion. An example is below.
+\t6+0 records in
+\t16+0 records out
+\t8192 bytes (8.2 kB, 8.0 KiB) copied, 0.00057009 s, 14.4 MB/s
+The first two lines are the 'volume' stats and the final line is the 'performance' stats.
+The volume stats indicate the number of complete and partial ibs-sized reads, or obs-sized writes that took place during the copy. The format of the volume stats is <complete>+<partial>. If records have been truncated (see conv=block), the volume stats will contain the number of truncated records.
+
+Permissible LEVEL values are:
+\t progress: Print periodic performance stats as the copy proceeds.
+\t noxfer: Print final volume stats, but not performance stats.
+\t none: Do not print any stats.
+
+Printing performance stats is also triggered by the INFO signal (where supported), or the USR1 signal. Setting the POSIXLY_CORRECT environment variable to any value (including an empty value) will cause the USR1 signal to be ignored.
+
+")
+        )
+        .arg(
+            clap::Arg::with_name(options::CONV)
+                .long(options::CONV)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("CONV")
+                .help("(alternatively conv=CONV[,CONV]) specifies a comma-separated list of conversion options or (for legacy reasons) file flags. Conversion options and file flags may be intermixed.
+
+Conversion options:
+\t One of {ascii, ebcdic, ibm} will perform an encoding conversion.
+\t\t 'ascii' converts from EBCDIC to ASCII. This is the inverse of the 'ebcdic' option.
+\t\t 'ebcdic' converts from ASCII to EBCDIC. This is the inverse of the 'ascii' option.
+\t\t 'ibm' converts from ASCII to EBCDIC, applying the conventions for '[', ']' and '~' specified in POSIX.
+
+\t One of {ucase, lcase} will perform a case conversion. Works in conjunction with option {ascii, ebcdic, ibm} to infer input encoding. If no other conversion option is specified, input is assumed to be ascii.
+\t\t 'ucase' converts from lower-case to upper-case
+\t\t 'lcase' converts from upper-case to lower-case.
+
+\t One of {block, unblock}. Convert between lines terminated by newline characters, and fixed-width lines padded by spaces (without any newlines). Both the 'block' and 'unblock' options require cbs=BYTES be specified.
+\t\t 'block' for each newline less than the size indicated by cbs=BYTES, remove the newline and pad with spaces up to cbs. Lines longer than cbs are truncated.
+\t\t 'unblock' for each block of input of the size indicated by cbs=BYTES, remove right-trailing spaces and replace with a newline character.
+
+\t 'sparse' attempts to seek the output when an obs-sized block consists of only zeros.
+\t 'swab' swaps each adjacent pair of bytes. If an odd number of bytes is present, the final byte is omitted.
+\t 'sync' pad each ibs-sided block with zeros. If 'block' or 'unblock' is specified, pad with spaces instead.
+
+Conversion Flags:
+\t One of {excl, nocreat}
+\t\t 'excl' the output file must be created. Fail if the output file is already present.
+\t\t 'nocreat' the output file will not be created. Fail if the output file in not already present.
+\t 'notrunc' the output file will not be truncated. If this option is not present, output will be truncated when opened.
+\t 'noerror' all read errors will be ignored. If this option is not present, dd will only ignore Error::Interrupted.
+\t 'fdatasync' data will be written before finishing.
+\t 'fsync' data and metadata will be written before finishing.
+
+")
+        )
+        .arg(
+            clap::Arg::with_name(options::IFLAG)
+                .long(options::IFLAG)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("FLAG")
+                .help("(alternatively iflag=FLAG[,FLAG]) a comma separated list of input flags which specify how the input source is treated. FLAG may be any of the input-flags or general-flags specified below.
+
+Input-Flags
+\t 'count_bytes' a value to count=N will be interpreted as bytes.
+\t 'skip_bytes' a value to skip=N will be interpreted as bytes.
+\t 'fullblock' wait for ibs bytes from each read. zero-length reads are still considered EOF.
+
+General-Flags
+\t 'direct' use direct I/O for data.
+\t 'directory' fail unless the given input (if used as an iflag) or output (if used as an oflag) is a directory.
+\t 'dsync' use synchronized I/O for data.
+\t 'sync' use synchronized I/O for data and metadata.
+\t 'nonblock' use non-blocking I/O.
+\t 'noatime' do not update access time.
+\t 'nocache' request that OS drop cache.
+\t 'noctty' do not assign a controlling tty.
+\t 'nofollow' do not follow system links.
+
+")
+        )
+        .arg(
+            clap::Arg::with_name(options::OFLAG)
+                .long(options::OFLAG)
+                .takes_value(true)
+                .require_equals(true)
+                .value_name("FLAG")
+                .help("(alternatively oflag=FLAG[,FLAG]) a comma separated list of output flags which specify how the output source is treated. FLAG may be any of the output-flags or general-flags specified below.
+
+Output-Flags
+\t 'append' open file in append mode. Consider setting conv=notrunc as well.
+\t 'seek_bytes' a value to seek=N will be interpreted as bytes.
+
+General-Flags
+\t 'direct' use direct I/O for data.
+\t 'directory' fail unless the given input (if used as an iflag) or output (if used as an oflag) is a directory.
+\t 'dsync' use synchronized I/O for data.
+\t 'sync' use synchronized I/O for data and metadata.
+\t 'nonblock' use non-blocking I/O.
+\t 'noatime' do not update access time.
+\t 'nocache' request that OS drop cache.
+\t 'noctty' do not assign a controlling tty.
+\t 'nofollow' do not follow system links.
+
+")
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_dd/parseargs.rs.html b/src/uu_dd/parseargs.rs.html new file mode 100644 index 000000000..8616b85e7 --- /dev/null +++ b/src/uu_dd/parseargs.rs.html @@ -0,0 +1,1333 @@ +parseargs.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Tyler Steele <tyler.steele@protonmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+// spell-checker:ignore ctty, ctable, iconvflags, oconvflags
+
+#[cfg(test)]
+mod unit_tests;
+
+use super::*;
+use std::error::Error;
+
+pub type Matches = clap::ArgMatches<'static>;
+
+/// Parser Errors describe errors with parser input
+#[derive(Debug, PartialEq)]
+pub enum ParseError {
+    MultipleFmtTable,
+    MultipleUCaseLCase,
+    MultipleBlockUnblock,
+    MultipleExclNoCreat,
+    FlagNoMatch(String),
+    ConvFlagNoMatch(String),
+    MultiplierStringParseFailure(String),
+    MultiplierStringOverflow(String),
+    BlockUnblockWithoutCBS,
+    StatusLevelNotRecognized(String),
+    Unimplemented(String),
+}
+
+impl std::fmt::Display for ParseError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::MultipleFmtTable => {
+                write!(
+                    f,
+                    "Only one of conv=ascii conv=ebcdic or conv=ibm may be specified"
+                )
+            }
+            Self::MultipleUCaseLCase => {
+                write!(f, "Only one of conv=lcase or conv=ucase may be specified")
+            }
+            Self::MultipleBlockUnblock => {
+                write!(f, "Only one of conv=block or conv=unblock may be specified")
+            }
+            Self::MultipleExclNoCreat => {
+                write!(f, "Only one ov conv=excl or conv=nocreat may be specified")
+            }
+            Self::FlagNoMatch(arg) => {
+                write!(f, "Unrecognized iflag=FLAG or oflag=FLAG -> {}", arg)
+            }
+            Self::ConvFlagNoMatch(arg) => {
+                write!(f, "Unrecognized conv=CONV -> {}", arg)
+            }
+            Self::MultiplierStringParseFailure(arg) => {
+                write!(f, "Unrecognized byte multiplier -> {}", arg)
+            }
+            Self::MultiplierStringOverflow(arg) => {
+                write!(
+                    f,
+                    "Multiplier string would overflow on current system -> {}",
+                    arg
+                )
+            }
+            Self::BlockUnblockWithoutCBS => {
+                write!(f, "conv=block or conv=unblock specified without cbs=N")
+            }
+            Self::StatusLevelNotRecognized(arg) => {
+                write!(f, "status=LEVEL not recognized -> {}", arg)
+            }
+            Self::Unimplemented(arg) => {
+                write!(f, "feature not implemented on this system -> {}", arg)
+            }
+        }
+    }
+}
+
+impl Error for ParseError {}
+
+/// Some flags specified as part of a conv=CONV[,CONV]... block
+/// relate to the input file, others to the output file.
+#[derive(Debug, PartialEq)]
+enum ConvFlag {
+    // Input
+    FmtAtoE,
+    FmtEtoA,
+    FmtAtoI,
+    Block,
+    Unblock,
+    UCase,
+    LCase,
+    Swab,
+    Sync,
+    NoError,
+    // Output
+    Sparse,
+    Excl,
+    NoCreat,
+    NoTrunc,
+    FDataSync,
+    FSync,
+}
+
+impl std::str::FromStr for ConvFlag {
+    type Err = ParseError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            // Input
+            "ascii" => Ok(Self::FmtEtoA),
+            "ebcdic" => Ok(Self::FmtAtoE),
+            "ibm" => Ok(Self::FmtAtoI),
+            "lcase" => Ok(Self::LCase),
+            "ucase" => Ok(Self::UCase),
+            "block" => Ok(Self::Block),
+            "unblock" => Ok(Self::Unblock),
+            "swab" => Ok(Self::Swab),
+            "sync" => Ok(Self::Sync),
+            "noerror" => Ok(Self::NoError),
+            // Output
+            "sparse" => Ok(Self::Sparse),
+            "excl" => Ok(Self::Excl),
+            "nocreat" => Ok(Self::NoCreat),
+            "notrunc" => Ok(Self::NoTrunc),
+            "fdatasync" => Ok(Self::FDataSync),
+            "fsync" => Ok(Self::FSync),
+            _ => Err(ParseError::ConvFlagNoMatch(String::from(s))),
+        }
+    }
+}
+
+#[derive(Debug, PartialEq)]
+enum Flag {
+    // Input only
+    FullBlock,
+    CountBytes,
+    SkipBytes,
+    // Either
+    #[allow(unused)]
+    Cio,
+    #[allow(unused)]
+    Direct,
+    #[allow(unused)]
+    Directory,
+    #[allow(unused)]
+    Dsync,
+    #[allow(unused)]
+    Sync,
+    #[allow(unused)]
+    NoCache,
+    #[allow(unused)]
+    NonBlock,
+    #[allow(unused)]
+    NoATime,
+    #[allow(unused)]
+    NoCtty,
+    #[allow(unused)]
+    NoFollow,
+    #[allow(unused)]
+    NoLinks,
+    #[allow(unused)]
+    Binary,
+    #[allow(unused)]
+    Text,
+    // Output only
+    Append,
+    SeekBytes,
+}
+
+impl std::str::FromStr for Flag {
+    type Err = ParseError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            // Input only
+            "fullblock" => Ok(Self::FullBlock),
+            "count_bytes" => Ok(Self::CountBytes),
+            "skip_bytes" => Ok(Self::SkipBytes),
+            // Either
+            "cio" =>
+            // Ok(Self::Cio),
+            {
+                Err(ParseError::Unimplemented(s.to_string()))
+            }
+            "direct" =>
+            // Ok(Self::Direct),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::Direct)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "directory" =>
+            // Ok(Self::Directory),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::Directory)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "dsync" =>
+            // Ok(Self::Dsync),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::Dsync)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "sync" =>
+            // Ok(Self::Sync),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::Sync)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "nocache" =>
+            // Ok(Self::NoCache),
+            {
+                Err(ParseError::Unimplemented(s.to_string()))
+            }
+            "nonblock" =>
+            // Ok(Self::NonBlock),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::NonBlock)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "noatime" =>
+            // Ok(Self::NoATime),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::NoATime)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "noctty" =>
+            // Ok(Self::NoCtty),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::NoCtty)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "nofollow" =>
+            // Ok(Self::NoFollow),
+            {
+                if cfg!(target_os = "linux") {
+                    Ok(Self::NoFollow)
+                } else {
+                    Err(ParseError::Unimplemented(s.to_string()))
+                }
+            }
+            "nolinks" =>
+            // Ok(Self::NoLinks),
+            {
+                Err(ParseError::Unimplemented(s.to_string()))
+            }
+            "binary" =>
+            // Ok(Self::Binary),
+            {
+                Err(ParseError::Unimplemented(s.to_string()))
+            }
+            "text" =>
+            // Ok(Self::Text),
+            {
+                Err(ParseError::Unimplemented(s.to_string()))
+            }
+            // Output only
+            "append" => Ok(Self::Append),
+            "seek_bytes" => Ok(Self::SeekBytes),
+            _ => Err(ParseError::FlagNoMatch(String::from(s))),
+        }
+    }
+}
+
+impl std::str::FromStr for StatusLevel {
+    type Err = ParseError;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
+        match s {
+            "none" => Ok(StatusLevel::None),
+            "noxfer" => Ok(StatusLevel::Noxfer),
+            "progress" => Ok(StatusLevel::Progress),
+            _ => Err(ParseError::StatusLevelNotRecognized(s.to_string())),
+        }
+    }
+}
+
+/// Parse bytes using str::parse, then map error if needed.
+fn parse_bytes_only(s: &str) -> Result<usize, ParseError> {
+    s.parse()
+        .map_err(|_| ParseError::MultiplierStringParseFailure(s.to_string()))
+}
+
+/// Parse byte and multiplier like 512, 5KiB, or 1G.
+/// Uses uucore::parse_size, and adds the 'w' and 'c' suffixes which are mentioned
+/// in dd's info page.
+fn parse_bytes_with_opt_multiplier(s: &str) -> Result<usize, ParseError> {
+    if let Some(idx) = s.rfind('c') {
+        parse_bytes_only(&s[..idx])
+    } else if let Some(idx) = s.rfind('w') {
+        let partial = parse_bytes_only(&s[..idx])?;
+
+        partial
+            .checked_mul(2)
+            .ok_or_else(|| ParseError::MultiplierStringOverflow(s.to_string()))
+    } else {
+        uucore::parse_size::parse_size(s).map_err(|e| match e {
+            uucore::parse_size::ParseSizeError::ParseFailure(s) => {
+                ParseError::MultiplierStringParseFailure(s)
+            }
+            uucore::parse_size::ParseSizeError::SizeTooBig(s) => {
+                ParseError::MultiplierStringOverflow(s)
+            }
+        })
+    }
+}
+
+pub fn parse_ibs(matches: &Matches) -> Result<usize, ParseError> {
+    if let Some(mixed_str) = matches.value_of(options::BS) {
+        parse_bytes_with_opt_multiplier(mixed_str)
+    } else if let Some(mixed_str) = matches.value_of(options::IBS) {
+        parse_bytes_with_opt_multiplier(mixed_str)
+    } else {
+        Ok(512)
+    }
+}
+
+fn parse_cbs(matches: &Matches) -> Result<Option<usize>, ParseError> {
+    if let Some(s) = matches.value_of(options::CBS) {
+        let bytes = parse_bytes_with_opt_multiplier(s)?;
+        Ok(Some(bytes))
+    } else {
+        Ok(None)
+    }
+}
+
+pub fn parse_status_level(matches: &Matches) -> Result<Option<StatusLevel>, ParseError> {
+    match matches.value_of(options::STATUS) {
+        Some(s) => {
+            let st = s.parse()?;
+            Ok(Some(st))
+        }
+        None => Ok(None),
+    }
+}
+
+pub fn parse_obs(matches: &Matches) -> Result<usize, ParseError> {
+    if let Some(mixed_str) = matches.value_of("bs") {
+        parse_bytes_with_opt_multiplier(mixed_str)
+    } else if let Some(mixed_str) = matches.value_of("obs") {
+        parse_bytes_with_opt_multiplier(mixed_str)
+    } else {
+        Ok(512)
+    }
+}
+
+fn parse_ctable(fmt: Option<ConvFlag>, case: Option<ConvFlag>) -> Option<&'static ConversionTable> {
+    fn parse_conv_and_case_table(
+        fmt: &ConvFlag,
+        case: &ConvFlag,
+    ) -> Option<&'static ConversionTable> {
+        match (fmt, case) {
+            (ConvFlag::FmtAtoE, ConvFlag::UCase) => Some(&ASCII_TO_EBCDIC_LCASE_TO_UCASE),
+            (ConvFlag::FmtAtoE, ConvFlag::LCase) => Some(&ASCII_TO_EBCDIC_UCASE_TO_LCASE),
+            (ConvFlag::FmtEtoA, ConvFlag::UCase) => Some(&EBCDIC_TO_ASCII_LCASE_TO_UCASE),
+            (ConvFlag::FmtEtoA, ConvFlag::LCase) => Some(&EBCDIC_TO_ASCII_UCASE_TO_LCASE),
+            (ConvFlag::FmtAtoI, ConvFlag::UCase) => Some(&ASCII_TO_IBM_UCASE_TO_LCASE),
+            (ConvFlag::FmtAtoI, ConvFlag::LCase) => Some(&ASCII_TO_IBM_LCASE_TO_UCASE),
+            (_, _) => None,
+        }
+    }
+    fn parse_conv_table_only(fmt: &ConvFlag) -> Option<&'static ConversionTable> {
+        match fmt {
+            ConvFlag::FmtAtoE => Some(&ASCII_TO_EBCDIC),
+            ConvFlag::FmtEtoA => Some(&EBCDIC_TO_ASCII),
+            ConvFlag::FmtAtoI => Some(&ASCII_TO_IBM),
+            _ => None,
+        }
+    }
+    // ------------------------------------------------------------------------
+    match (fmt, case) {
+        // Both [ascii | ebcdic | ibm] and [lcase | ucase] specified
+        (Some(fmt), Some(case)) => parse_conv_and_case_table(&fmt, &case),
+        // Only [ascii | ebcdic | ibm] specified
+        (Some(fmt), None) => parse_conv_table_only(&fmt),
+        // Only [lcase | ucase] specified
+        (None, Some(ConvFlag::UCase)) => Some(&ASCII_LCASE_TO_UCASE),
+        (None, Some(ConvFlag::LCase)) => Some(&ASCII_UCASE_TO_LCASE),
+        // ST else...
+        (_, _) => None,
+    }
+}
+
+fn parse_flag_list<T: std::str::FromStr<Err = ParseError>>(
+    tag: &str,
+    matches: &Matches,
+) -> Result<Vec<T>, ParseError> {
+    let mut flags = Vec::new();
+
+    if let Some(comma_str) = matches.value_of(tag) {
+        for s in comma_str.split(',') {
+            let flag = s.parse()?;
+            flags.push(flag);
+        }
+    }
+
+    Ok(flags)
+}
+
+/// Parse Conversion Options (Input Variety)
+/// Construct and validate a IConvFlags
+pub fn parse_conv_flag_input(matches: &Matches) -> Result<IConvFlags, ParseError> {
+    let mut iconvflags = IConvFlags::default();
+    let mut fmt = None;
+    let mut case = None;
+    let mut is_sync = false;
+
+    let flags = parse_flag_list(options::CONV, matches)?;
+    let cbs = parse_cbs(matches)?;
+
+    for flag in flags {
+        match flag {
+            ConvFlag::FmtEtoA => {
+                if fmt.is_some() {
+                    return Err(ParseError::MultipleFmtTable);
+                } else {
+                    fmt = Some(flag);
+                }
+            }
+            ConvFlag::FmtAtoE => {
+                if fmt.is_some() {
+                    return Err(ParseError::MultipleFmtTable);
+                } else {
+                    fmt = Some(flag);
+                }
+            }
+            ConvFlag::FmtAtoI => {
+                if fmt.is_some() {
+                    return Err(ParseError::MultipleFmtTable);
+                } else {
+                    fmt = Some(flag);
+                }
+            }
+            ConvFlag::UCase => {
+                if case.is_some() {
+                    return Err(ParseError::MultipleUCaseLCase);
+                } else {
+                    case = Some(flag)
+                }
+            }
+            ConvFlag::LCase => {
+                if case.is_some() {
+                    return Err(ParseError::MultipleUCaseLCase);
+                } else {
+                    case = Some(flag)
+                }
+            }
+            ConvFlag::Block => match (cbs, iconvflags.unblock) {
+                (Some(cbs), None) => iconvflags.block = Some(cbs),
+                (None, _) => return Err(ParseError::BlockUnblockWithoutCBS),
+                (_, Some(_)) => return Err(ParseError::MultipleBlockUnblock),
+            },
+            ConvFlag::Unblock => match (cbs, iconvflags.block) {
+                (Some(cbs), None) => iconvflags.unblock = Some(cbs),
+                (None, _) => return Err(ParseError::BlockUnblockWithoutCBS),
+                (_, Some(_)) => return Err(ParseError::MultipleBlockUnblock),
+            },
+            ConvFlag::Swab => iconvflags.swab = true,
+            ConvFlag::Sync => is_sync = true,
+            ConvFlag::NoError => iconvflags.noerror = true,
+            _ => {}
+        }
+    }
+
+    // The final conversion table depends on both
+    // fmt (eg. ASCII -> EBCDIC)
+    // case (eg. UCASE -> LCASE)
+    // So the final value can't be set until all flags are parsed.
+    let ctable = parse_ctable(fmt, case);
+
+    // The final value of sync depends on block/unblock
+    // block implies sync with ' '
+    // unblock implies sync with 0
+    // So the final value can't be set until all flags are parsed.
+    let sync = if is_sync && (iconvflags.block.is_some() || iconvflags.unblock.is_some()) {
+        Some(b' ')
+    } else if is_sync {
+        Some(0u8)
+    } else {
+        None
+    };
+
+    Ok(IConvFlags {
+        ctable,
+        sync,
+        ..iconvflags
+    })
+}
+
+/// Parse Conversion Options (Output Variety)
+/// Construct and validate a OConvFlags
+pub fn parse_conv_flag_output(matches: &Matches) -> Result<OConvFlags, ParseError> {
+    let mut oconvflags = OConvFlags::default();
+
+    let flags = parse_flag_list(options::CONV, matches)?;
+
+    for flag in flags {
+        match flag {
+            ConvFlag::Sparse => oconvflags.sparse = true,
+            ConvFlag::Excl => {
+                if !oconvflags.nocreat {
+                    oconvflags.excl = true;
+                } else {
+                    return Err(ParseError::MultipleExclNoCreat);
+                }
+            }
+            ConvFlag::NoCreat => {
+                if !oconvflags.excl {
+                    oconvflags.nocreat = true;
+                } else {
+                    return Err(ParseError::MultipleExclNoCreat);
+                }
+            }
+            ConvFlag::NoTrunc => oconvflags.notrunc = true,
+            ConvFlag::FDataSync => oconvflags.fdatasync = true,
+            ConvFlag::FSync => oconvflags.fsync = true,
+            _ => {}
+        }
+    }
+
+    Ok(oconvflags)
+}
+
+/// Parse IFlags struct from CL-input
+pub fn parse_iflags(matches: &Matches) -> Result<IFlags, ParseError> {
+    let mut iflags = IFlags::default();
+
+    let flags = parse_flag_list(options::IFLAG, matches)?;
+
+    for flag in flags {
+        match flag {
+            Flag::Cio => iflags.cio = true,
+            Flag::Direct => iflags.direct = true,
+            Flag::Directory => iflags.directory = true,
+            Flag::Dsync => iflags.dsync = true,
+            Flag::Sync => iflags.sync = true,
+            Flag::NoCache => iflags.nocache = true,
+            Flag::NonBlock => iflags.nonblock = true,
+            Flag::NoATime => iflags.noatime = true,
+            Flag::NoCtty => iflags.noctty = true,
+            Flag::NoFollow => iflags.nofollow = true,
+            Flag::NoLinks => iflags.nolinks = true,
+            Flag::Binary => iflags.binary = true,
+            Flag::Text => iflags.text = true,
+            Flag::FullBlock => iflags.fullblock = true,
+            Flag::CountBytes => iflags.count_bytes = true,
+            Flag::SkipBytes => iflags.skip_bytes = true,
+            _ => {}
+        }
+    }
+
+    Ok(iflags)
+}
+
+/// Parse OFlags struct from CL-input
+pub fn parse_oflags(matches: &Matches) -> Result<OFlags, ParseError> {
+    let mut oflags = OFlags::default();
+
+    let flags = parse_flag_list(options::OFLAG, matches)?;
+
+    for flag in flags {
+        match flag {
+            Flag::Append => oflags.append = true,
+            Flag::Cio => oflags.cio = true,
+            Flag::Direct => oflags.direct = true,
+            Flag::Directory => oflags.directory = true,
+            Flag::Dsync => oflags.dsync = true,
+            Flag::Sync => oflags.sync = true,
+            Flag::NoCache => oflags.nocache = true,
+            Flag::NonBlock => oflags.nonblock = true,
+            Flag::NoATime => oflags.noatime = true,
+            Flag::NoCtty => oflags.noctty = true,
+            Flag::NoFollow => oflags.nofollow = true,
+            Flag::NoLinks => oflags.nolinks = true,
+            Flag::Binary => oflags.binary = true,
+            Flag::Text => oflags.text = true,
+            Flag::SeekBytes => oflags.seek_bytes = true,
+            _ => {}
+        }
+    }
+
+    Ok(oflags)
+}
+
+/// Parse the amount of the input file to skip.
+pub fn parse_skip_amt(
+    ibs: &usize,
+    iflags: &IFlags,
+    matches: &Matches,
+) -> Result<Option<usize>, ParseError> {
+    if let Some(amt) = matches.value_of(options::SKIP) {
+        let n = parse_bytes_with_opt_multiplier(amt)?;
+        if iflags.skip_bytes {
+            Ok(Some(n))
+        } else {
+            Ok(Some(ibs * n))
+        }
+    } else {
+        Ok(None)
+    }
+}
+
+/// Parse the amount of the output file to seek.
+pub fn parse_seek_amt(
+    obs: &usize,
+    oflags: &OFlags,
+    matches: &Matches,
+) -> Result<Option<usize>, ParseError> {
+    if let Some(amt) = matches.value_of(options::SEEK) {
+        let n = parse_bytes_with_opt_multiplier(amt)?;
+        if oflags.seek_bytes {
+            Ok(Some(n))
+        } else {
+            Ok(Some(obs * n))
+        }
+    } else {
+        Ok(None)
+    }
+}
+
+/// Parse the value of count=N and the type of N implied by iflags
+pub fn parse_count(iflags: &IFlags, matches: &Matches) -> Result<Option<CountType>, ParseError> {
+    if let Some(amt) = matches.value_of(options::COUNT) {
+        let n = parse_bytes_with_opt_multiplier(amt)?;
+        if iflags.count_bytes {
+            Ok(Some(CountType::Bytes(n)))
+        } else {
+            Ok(Some(CountType::Reads(n)))
+        }
+    } else {
+        Ok(None)
+    }
+}
+
+/// Parse whether the args indicate the input is not ascii
+pub fn parse_input_non_ascii(matches: &Matches) -> Result<bool, ParseError> {
+    if let Some(conv_opts) = matches.value_of(options::CONV) {
+        Ok(conv_opts.contains("ascii"))
+    } else {
+        Ok(false)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_df/df.rs.html b/src/uu_df/df.rs.html new file mode 100644 index 000000000..9b6a65a05 --- /dev/null +++ b/src/uu_df/df.rs.html @@ -0,0 +1,1083 @@ +df.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Fangxu Hu <framlog@gmail.com>
+// (c) Sylvestre Ledru <sylvestre@debian.org>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+use uucore::error::UError;
+use uucore::error::UResult;
+#[cfg(unix)]
+use uucore::fsext::statfs_fn;
+use uucore::fsext::{read_fs_list, FsUsage, MountInfo};
+
+use clap::{crate_version, App, Arg};
+
+use number_prefix::NumberPrefix;
+use std::cell::Cell;
+use std::collections::HashMap;
+use std::collections::HashSet;
+
+use std::error::Error;
+#[cfg(unix)]
+use std::ffi::CString;
+use std::fmt::Display;
+#[cfg(unix)]
+use std::mem;
+
+#[cfg(windows)]
+use std::path::Path;
+
+static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
+                      or all file systems by default.";
+
+static OPT_ALL: &str = "all";
+static OPT_BLOCKSIZE: &str = "blocksize";
+static OPT_DIRECT: &str = "direct";
+static OPT_TOTAL: &str = "total";
+static OPT_HUMAN_READABLE: &str = "human-readable";
+static OPT_HUMAN_READABLE_2: &str = "human-readable-2";
+static OPT_INODES: &str = "inodes";
+static OPT_KILO: &str = "kilo";
+static OPT_LOCAL: &str = "local";
+static OPT_NO_SYNC: &str = "no-sync";
+static OPT_OUTPUT: &str = "output";
+static OPT_PATHS: &str = "paths";
+static OPT_PORTABILITY: &str = "portability";
+static OPT_SYNC: &str = "sync";
+static OPT_TYPE: &str = "type";
+static OPT_PRINT_TYPE: &str = "print-type";
+static OPT_EXCLUDE_TYPE: &str = "exclude-type";
+
+/// Store names of file systems as a selector.
+/// Note: `exclude` takes priority over `include`.
+struct FsSelector {
+    include: HashSet<String>,
+    exclude: HashSet<String>,
+}
+
+struct Options {
+    show_local_fs: bool,
+    show_all_fs: bool,
+    show_listed_fs: bool,
+    show_fs_type: bool,
+    show_inode_instead: bool,
+    // block_size: usize,
+    human_readable_base: i64,
+    fs_selector: FsSelector,
+}
+
+#[derive(Debug, Clone)]
+struct Filesystem {
+    mount_info: MountInfo,
+    usage: FsUsage,
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+impl FsSelector {
+    fn new() -> FsSelector {
+        FsSelector {
+            include: HashSet::new(),
+            exclude: HashSet::new(),
+        }
+    }
+
+    #[inline(always)]
+    fn include(&mut self, fs_type: String) {
+        self.include.insert(fs_type);
+    }
+
+    #[inline(always)]
+    fn exclude(&mut self, fs_type: String) {
+        self.exclude.insert(fs_type);
+    }
+
+    fn should_select(&self, fs_type: &str) -> bool {
+        if self.exclude.contains(fs_type) {
+            return false;
+        }
+        self.include.is_empty() || self.include.contains(fs_type)
+    }
+}
+
+impl Options {
+    fn new() -> Options {
+        Options {
+            show_local_fs: false,
+            show_all_fs: false,
+            show_listed_fs: false,
+            show_fs_type: false,
+            show_inode_instead: false,
+            // block_size: match env::var("BLOCKSIZE") {
+            //     Ok(size) => size.parse().unwrap(),
+            //     Err(_) => 512,
+            // },
+            human_readable_base: -1,
+            fs_selector: FsSelector::new(),
+        }
+    }
+}
+
+impl Filesystem {
+    // TODO: resolve uuid in `mount_info.dev_name` if exists
+    fn new(mount_info: MountInfo) -> Option<Filesystem> {
+        let _stat_path = if !mount_info.mount_dir.is_empty() {
+            mount_info.mount_dir.clone()
+        } else {
+            #[cfg(unix)]
+            {
+                mount_info.dev_name.clone()
+            }
+            #[cfg(windows)]
+            {
+                // On windows, we expect the volume id
+                mount_info.dev_id.clone()
+            }
+        };
+        #[cfg(unix)]
+        unsafe {
+            let path = CString::new(_stat_path).unwrap();
+            let mut statvfs = mem::zeroed();
+            if statfs_fn(path.as_ptr(), &mut statvfs) < 0 {
+                None
+            } else {
+                Some(Filesystem {
+                    mount_info,
+                    usage: FsUsage::new(statvfs),
+                })
+            }
+        }
+        #[cfg(windows)]
+        Some(Filesystem {
+            mount_info,
+            usage: FsUsage::new(Path::new(&_stat_path)),
+        })
+    }
+}
+
+fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Vec<MountInfo> {
+    vmi.into_iter()
+        .filter_map(|mi| {
+            if (mi.remote && opt.show_local_fs)
+                || (mi.dummy && !opt.show_all_fs && !opt.show_listed_fs)
+                || !opt.fs_selector.should_select(&mi.fs_type)
+            {
+                None
+            } else {
+                if paths.is_empty() {
+                    // No path specified
+                    return Some((mi.dev_id.clone(), mi));
+                }
+                if paths.contains(&mi.mount_dir) {
+                    // One or more paths have been provided
+                    Some((mi.dev_id.clone(), mi))
+                } else {
+                    // Not a path we want to see
+                    None
+                }
+            }
+        })
+        .fold(
+            HashMap::<String, Cell<MountInfo>>::new(),
+            |mut acc, (id, mi)| {
+                #[allow(clippy::map_entry)]
+                {
+                    if acc.contains_key(&id) {
+                        let seen = acc[&id].replace(mi.clone());
+                        let target_nearer_root = seen.mount_dir.len() > mi.mount_dir.len();
+                        // With bind mounts, prefer items nearer the root of the source
+                        let source_below_root = !seen.mount_root.is_empty()
+                            && !mi.mount_root.is_empty()
+                            && seen.mount_root.len() < mi.mount_root.len();
+                        // let "real" devices with '/' in the name win.
+                        if (!mi.dev_name.starts_with('/') || seen.dev_name.starts_with('/'))
+                            // let points towards the root of the device win.
+                            && (!target_nearer_root || source_below_root)
+                            // let an entry over-mounted on a new device win...
+                            && (seen.dev_name == mi.dev_name
+                            /* ... but only when matching an existing mnt point,
+                            to avoid problematic replacement when given
+                            inaccurate mount lists, seen with some chroot
+                            environments for example.  */
+                            || seen.mount_dir != mi.mount_dir)
+                        {
+                            acc[&id].replace(seen);
+                        }
+                    } else {
+                        acc.insert(id, Cell::new(mi));
+                    }
+                    acc
+                }
+            },
+        )
+        .into_iter()
+        .map(|ent| ent.1.into_inner())
+        .collect::<Vec<_>>()
+}
+
+/// Convert `value` to a human readable string based on `base`.
+/// e.g. It returns 1G when value is 1 * 1024 * 1024 * 1024 and base is 1024.
+/// Note: It returns `value` if `base` isn't positive.
+fn human_readable(value: u64, base: i64) -> UResult<String> {
+    let base_str = match base {
+        d if d < 0 => value.to_string(),
+
+        // ref: [Binary prefix](https://en.wikipedia.org/wiki/Binary_prefix) @@ <https://archive.is/cnwmF>
+        // ref: [SI/metric prefix](https://en.wikipedia.org/wiki/Metric_prefix) @@ <https://archive.is/QIuLj>
+        1000 => match NumberPrefix::decimal(value as f64) {
+            NumberPrefix::Standalone(bytes) => bytes.to_string(),
+            NumberPrefix::Prefixed(prefix, bytes) => format!("{:.1}{}", bytes, prefix.symbol()),
+        },
+
+        1024 => match NumberPrefix::binary(value as f64) {
+            NumberPrefix::Standalone(bytes) => bytes.to_string(),
+            NumberPrefix::Prefixed(prefix, bytes) => format!("{:.1}{}", bytes, prefix.symbol()),
+        },
+
+        _ => return Err(DfError::InvalidBaseValue(base.to_string()).into()),
+    };
+
+    Ok(base_str)
+}
+
+fn use_size(free_size: u64, total_size: u64) -> String {
+    if total_size == 0 {
+        return String::from("-");
+    }
+    return format!(
+        "{:.0}%",
+        100f64 - 100f64 * (free_size as f64 / total_size as f64)
+    );
+}
+
+#[derive(Debug)]
+enum DfError {
+    InvalidBaseValue(String),
+}
+
+impl Display for DfError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            DfError::InvalidBaseValue(s) => write!(f, "Internal error: Unknown base value {}", s),
+        }
+    }
+}
+
+impl Error for DfError {}
+
+impl UError for DfError {
+    fn code(&self) -> i32 {
+        match self {
+            DfError::InvalidBaseValue(_) => 1,
+        }
+    }
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let paths: Vec<String> = matches
+        .values_of(OPT_PATHS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    #[cfg(windows)]
+    {
+        if matches.is_present(OPT_INODES) {
+            println!("{}: doesn't support -i option", uucore::util_name());
+            return Ok(());
+        }
+    }
+
+    let mut opt = Options::new();
+    if matches.is_present(OPT_LOCAL) {
+        opt.show_local_fs = true;
+    }
+    if matches.is_present(OPT_ALL) {
+        opt.show_all_fs = true;
+    }
+    if matches.is_present(OPT_INODES) {
+        opt.show_inode_instead = true;
+    }
+    if matches.is_present(OPT_PRINT_TYPE) {
+        opt.show_fs_type = true;
+    }
+    if matches.is_present(OPT_HUMAN_READABLE) {
+        opt.human_readable_base = 1024;
+    }
+    if matches.is_present(OPT_HUMAN_READABLE_2) {
+        opt.human_readable_base = 1000;
+    }
+    for fs_type in matches.values_of_lossy(OPT_TYPE).unwrap_or_default() {
+        opt.fs_selector.include(fs_type.to_owned());
+    }
+    for fs_type in matches
+        .values_of_lossy(OPT_EXCLUDE_TYPE)
+        .unwrap_or_default()
+    {
+        opt.fs_selector.exclude(fs_type.to_owned());
+    }
+
+    let fs_list = filter_mount_list(read_fs_list(), &paths, &opt)
+        .into_iter()
+        .filter_map(Filesystem::new)
+        .filter(|fs| fs.usage.blocks != 0 || opt.show_all_fs || opt.show_listed_fs)
+        .collect::<Vec<_>>();
+
+    // set headers
+    let mut header = vec!["Filesystem"];
+    if opt.show_fs_type {
+        header.push("Type");
+    }
+    header.extend_from_slice(&if opt.show_inode_instead {
+        // spell-checker:disable-next-line
+        ["Inodes", "Iused", "IFree", "IUses%"]
+    } else {
+        [
+            if opt.human_readable_base == -1 {
+                "1k-blocks"
+            } else {
+                "Size"
+            },
+            "Used",
+            "Available",
+            "Use%",
+        ]
+    });
+    if cfg!(target_os = "macos") && !opt.show_inode_instead {
+        header.insert(header.len() - 1, "Capacity");
+    }
+    header.push("Mounted on");
+
+    for (idx, title) in header.iter().enumerate() {
+        if idx == 0 || idx == header.len() - 1 {
+            print!("{0: <16} ", title);
+        } else if opt.show_fs_type && idx == 1 {
+            print!("{0: <5} ", title);
+        } else if idx == header.len() - 2 {
+            print!("{0: >5} ", title);
+        } else {
+            print!("{0: >12} ", title);
+        }
+    }
+    println!();
+    for fs in fs_list.iter() {
+        print!("{0: <16} ", fs.mount_info.dev_name);
+        if opt.show_fs_type {
+            print!("{0: <5} ", fs.mount_info.fs_type);
+        }
+        if opt.show_inode_instead {
+            print!(
+                "{0: >12} ",
+                human_readable(fs.usage.files, opt.human_readable_base)?
+            );
+            print!(
+                "{0: >12} ",
+                human_readable(fs.usage.files - fs.usage.ffree, opt.human_readable_base)?
+            );
+            print!(
+                "{0: >12} ",
+                human_readable(fs.usage.ffree, opt.human_readable_base)?
+            );
+            print!(
+                "{0: >5} ",
+                format!(
+                    "{0:.1}%",
+                    100f64 - 100f64 * (fs.usage.ffree as f64 / fs.usage.files as f64)
+                )
+            );
+        } else {
+            let total_size = fs.usage.blocksize * fs.usage.blocks;
+            let free_size = fs.usage.blocksize * fs.usage.bfree;
+            print!(
+                "{0: >12} ",
+                human_readable(total_size, opt.human_readable_base)?
+            );
+            print!(
+                "{0: >12} ",
+                human_readable(total_size - free_size, opt.human_readable_base)?
+            );
+            print!(
+                "{0: >12} ",
+                human_readable(free_size, opt.human_readable_base)?
+            );
+            if cfg!(target_os = "macos") {
+                let used = fs.usage.blocks - fs.usage.bfree;
+                let blocks = used + fs.usage.bavail;
+                print!("{0: >12} ", use_size(used, blocks));
+            }
+            print!("{0: >5} ", use_size(free_size, total_size));
+        }
+        print!("{0: <16}", fs.mount_info.mount_dir);
+        println!();
+    }
+
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_ALL)
+                .short("a")
+                .long("all")
+                .help("include dummy file systems"),
+        )
+        .arg(
+            Arg::with_name(OPT_BLOCKSIZE)
+                .short("B")
+                .long("block-size")
+                .takes_value(true)
+                .help(
+                    "scale sizes by SIZE before printing them; e.g.\
+                     '-BM' prints sizes in units of 1,048,576 bytes",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_DIRECT)
+                .long("direct")
+                .help("show statistics for a file instead of mount point"),
+        )
+        .arg(
+            Arg::with_name(OPT_TOTAL)
+                .long("total")
+                .help("produce a grand total"),
+        )
+        .arg(
+            Arg::with_name(OPT_HUMAN_READABLE)
+                .short("h")
+                .long("human-readable")
+                .conflicts_with(OPT_HUMAN_READABLE_2)
+                .help("print sizes in human readable format (e.g., 1K 234M 2G)"),
+        )
+        .arg(
+            Arg::with_name(OPT_HUMAN_READABLE_2)
+                .short("H")
+                .long("si")
+                .conflicts_with(OPT_HUMAN_READABLE)
+                .help("likewise, but use powers of 1000 not 1024"),
+        )
+        .arg(
+            Arg::with_name(OPT_INODES)
+                .short("i")
+                .long("inodes")
+                .help("list inode information instead of block usage"),
+        )
+        .arg(
+            Arg::with_name(OPT_KILO)
+                .short("k")
+                .help("like --block-size=1K"),
+        )
+        .arg(
+            Arg::with_name(OPT_LOCAL)
+                .short("l")
+                .long("local")
+                .help("limit listing to local file systems"),
+        )
+        .arg(
+            Arg::with_name(OPT_NO_SYNC)
+                .long("no-sync")
+                .conflicts_with(OPT_SYNC)
+                .help("do not invoke sync before getting usage info (default)"),
+        )
+        .arg(
+            Arg::with_name(OPT_OUTPUT)
+                .long("output")
+                .takes_value(true)
+                .use_delimiter(true)
+                .help(
+                    "use the output format defined by FIELD_LIST,\
+                     or print all fields if FIELD_LIST is omitted.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_PORTABILITY)
+                .short("P")
+                .long("portability")
+                .help("use the POSIX output format"),
+        )
+        .arg(
+            Arg::with_name(OPT_SYNC)
+                .long("sync")
+                .conflicts_with(OPT_NO_SYNC)
+                .help("invoke sync before getting usage info"),
+        )
+        .arg(
+            Arg::with_name(OPT_TYPE)
+                .short("t")
+                .long("type")
+                .takes_value(true)
+                .use_delimiter(true)
+                .help("limit listing to file systems of type TYPE"),
+        )
+        .arg(
+            Arg::with_name(OPT_PRINT_TYPE)
+                .short("T")
+                .long("print-type")
+                .help("print file system type"),
+        )
+        .arg(
+            Arg::with_name(OPT_EXCLUDE_TYPE)
+                .short("x")
+                .long("exclude-type")
+                .takes_value(true)
+                .use_delimiter(true)
+                .help("limit listing to file systems not of type TYPE"),
+        )
+        .arg(Arg::with_name(OPT_PATHS).multiple(true))
+        .help("Filesystem(s) to list")
+}
+
+
\ No newline at end of file diff --git a/src/uu_dircolors/colors.rs.html b/src/uu_dircolors/colors.rs.html new file mode 100644 index 000000000..2b3a50a58 --- /dev/null +++ b/src/uu_dircolors/colors.rs.html @@ -0,0 +1,391 @@ +colors.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+
+// spell-checker:ignore (ToDO) EIGHTBIT ETERM MULTIHARDLINK cpio dtterm jfbterm konsole kterm mlterm rmvb rxvt stat'able svgz tmux webm xspf
+
+pub const INTERNAL_DB: &str = r#"# Configuration file for dircolors, a utility to help you set the
+# LS_COLORS environment variable used by GNU ls with the --color option.
+# Copyright (C) 1996-2016 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.
+# The keywords COLOR, OPTIONS, and EIGHTBIT (honored by the
+# slackware version of dircolors) are recognized but ignored.
+# 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-xterm
+TERM con[0-9]*x[0-9]*
+TERM cons25
+TERM console
+TERM cygwin
+TERM dtterm
+TERM eterm-color
+TERM gnome
+TERM gnome-256color
+TERM hurd
+TERM jfbterm
+TERM konsole
+TERM kterm
+TERM linux
+TERM linux-c
+TERM mach-color
+TERM mach-gnu-color
+TERM mlterm
+TERM putty
+TERM putty-256color
+TERM rxvt*
+TERM screen*
+TERM st
+TERM st-256color
+TERM terminator
+TERM tmux*
+TERM vt100
+TERM xterm*
+# 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:
+# Attribute codes:
+# 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
+# Text color codes:
+# 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
+#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
+ # 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
+# This is for files with execute permission:
+EXEC 01;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.
+# (and any comments you want to add after a '#')
+# If you use DOS-style suffixes, you may want to uncomment the following:
+#.cmd 01;32 # executables (bright green)
+#.exe 01;32
+#.com 01;32
+#.btm 01;32
+#.bat 01;32
+# Or if you want to colorize scripts even if they do not have the
+# executable bit actually set.
+#.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
+.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
+# image formats
+.jpg 01;35
+.jpeg 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
+# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
+.ogv 01;35
+.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
+# http://wiki.xiph.org/index.php/MIME_Types_and_File_Extensions
+.oga 00;36
+.opus 00;36
+.spx 00;36
+.xspf 00;36"#;
+
+
\ No newline at end of file diff --git a/src/uu_dircolors/dircolors.rs.html b/src/uu_dircolors/dircolors.rs.html new file mode 100644 index 000000000..b3f863521 --- /dev/null +++ b/src/uu_dircolors/dircolors.rs.html @@ -0,0 +1,719 @@ +dircolors.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+// (c) Mitchell Mebane <mitchell.mebane@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) clrtoeol dircolors eightbit endcode fnmatch leftcode multihardlink rightcode setenv sgid suid
+
+#[macro_use]
+extern crate uucore;
+
+use std::borrow::Borrow;
+use std::env;
+use std::fs::File;
+use std::io::{BufRead, BufReader};
+
+use clap::{crate_version, App, Arg};
+
+mod options {
+    pub const BOURNE_SHELL: &str = "bourne-shell";
+    pub const C_SHELL: &str = "c-shell";
+    pub const PRINT_DATABASE: &str = "print-database";
+    pub const FILE: &str = "FILE";
+}
+
+static SYNTAX: &str = "[OPTION]... [FILE]";
+static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
+static LONG_HELP: &str = "
+ If FILE is specified, read it to determine which colors to use for which
+ file types and extensions.  Otherwise, a precompiled database is used.
+ For details on the format of these files, run 'dircolors --print-database'
+";
+
+mod colors;
+use self::colors::INTERNAL_DB;
+
+#[derive(PartialEq, Debug)]
+pub enum OutputFmt {
+    Shell,
+    CShell,
+    Unknown,
+}
+
+pub fn guess_syntax() -> OutputFmt {
+    use std::path::Path;
+    match env::var("SHELL") {
+        Ok(ref s) if !s.is_empty() => {
+            let shell_path: &Path = s.as_ref();
+            if let Some(name) = shell_path.file_name() {
+                if name == "csh" || name == "tcsh" {
+                    OutputFmt::CShell
+                } else {
+                    OutputFmt::Shell
+                }
+            } else {
+                OutputFmt::Shell
+            }
+        }
+        _ => OutputFmt::Unknown,
+    }
+}
+
+fn usage() -> String {
+    format!("{0} {1}", uucore::execution_phrase(), SYNTAX)
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(&args);
+
+    let files = matches
+        .values_of(options::FILE)
+        .map_or(vec![], |file_values| file_values.collect());
+
+    // clap provides .conflicts_with / .conflicts_with_all, but we want to
+    // manually handle conflicts so we can match the output of GNU coreutils
+    if (matches.is_present(options::C_SHELL) || matches.is_present(options::BOURNE_SHELL))
+        && matches.is_present(options::PRINT_DATABASE)
+    {
+        show_usage_error!(
+            "the options to output dircolors' internal database and\nto select a shell \
+             syntax are mutually exclusive"
+        );
+        return 1;
+    }
+
+    if matches.is_present(options::PRINT_DATABASE) {
+        if !files.is_empty() {
+            show_usage_error!(
+                "extra operand '{}'\nfile operands cannot be combined with \
+                 --print-database (-p)",
+                files[0]
+            );
+            return 1;
+        }
+        println!("{}", INTERNAL_DB);
+        return 0;
+    }
+
+    let mut out_format = OutputFmt::Unknown;
+    if matches.is_present(options::C_SHELL) {
+        out_format = OutputFmt::CShell;
+    } else if matches.is_present(options::BOURNE_SHELL) {
+        out_format = OutputFmt::Shell;
+    }
+
+    if out_format == OutputFmt::Unknown {
+        match guess_syntax() {
+            OutputFmt::Unknown => {
+                show_error!("no SHELL environment variable, and no shell type option given");
+                return 1;
+            }
+            fmt => out_format = fmt,
+        }
+    }
+
+    let result;
+    if files.is_empty() {
+        result = parse(INTERNAL_DB.lines(), out_format, "")
+    } else {
+        if files.len() > 1 {
+            show_usage_error!("extra operand '{}'", files[1]);
+            return 1;
+        }
+        match File::open(files[0]) {
+            Ok(f) => {
+                let fin = BufReader::new(f);
+                result = parse(fin.lines().filter_map(Result::ok), out_format, files[0])
+            }
+            Err(e) => {
+                show_error!("{}: {}", files[0], e);
+                return 1;
+            }
+        }
+    }
+    match result {
+        Ok(s) => {
+            println!("{}", s);
+            0
+        }
+        Err(s) => {
+            show_error!("{}", s);
+            1
+        }
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(SUMMARY)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::BOURNE_SHELL)
+                .long("sh")
+                .short("b")
+                .visible_alias("bourne-shell")
+                .help("output Bourne shell code to set LS_COLORS")
+                .display_order(1),
+        )
+        .arg(
+            Arg::with_name(options::C_SHELL)
+                .long("csh")
+                .short("c")
+                .visible_alias("c-shell")
+                .help("output C shell code to set LS_COLORS")
+                .display_order(2),
+        )
+        .arg(
+            Arg::with_name(options::PRINT_DATABASE)
+                .long("print-database")
+                .short("p")
+                .help("print the byte counts")
+                .display_order(3),
+        )
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+}
+
+pub trait StrUtils {
+    /// Remove comments and trim whitespace
+    fn purify(&self) -> &Self;
+    /// Like split_whitespace() but only produce 2 components
+    fn split_two(&self) -> (&str, &str);
+    fn fnmatch(&self, pattern: &str) -> bool;
+}
+
+impl StrUtils for str {
+    fn purify(&self) -> &Self {
+        let mut line = self;
+        for (n, _) in self
+            .as_bytes()
+            .iter()
+            .enumerate()
+            .filter(|(_, c)| **c == b'#')
+        {
+            // Ignore the content after '#'
+            // only if it is preceded by at least one whitespace
+            match self[..n].chars().last() {
+                Some(c) if c.is_whitespace() => {
+                    line = &self[..n - c.len_utf8()];
+                    break;
+                }
+                None => {
+                    // n == 0
+                    line = &self[..0];
+                    break;
+                }
+                _ => (),
+            }
+        }
+        line.trim()
+    }
+
+    fn split_two(&self) -> (&str, &str) {
+        if let Some(b) = self.find(char::is_whitespace) {
+            let key = &self[..b];
+            if let Some(e) = self[b..].find(|c: char| !c.is_whitespace()) {
+                (key, &self[b + e..])
+            } else {
+                (key, "")
+            }
+        } else {
+            ("", "")
+        }
+    }
+
+    fn fnmatch(&self, pat: &str) -> bool {
+        pat.parse::<glob::Pattern>().unwrap().matches(self)
+    }
+}
+
+#[derive(PartialEq)]
+enum ParseState {
+    Global,
+    Matched,
+    Continue,
+    Pass,
+}
+use std::collections::HashMap;
+use uucore::InvalidEncodingHandling;
+
+fn parse<T>(lines: T, fmt: OutputFmt, fp: &str) -> Result<String, String>
+where
+    T: IntoIterator,
+    T::Item: Borrow<str>,
+{
+    // 1440 > $(dircolors | wc -m)
+    let mut result = String::with_capacity(1440);
+    match fmt {
+        OutputFmt::Shell => result.push_str("LS_COLORS='"),
+        OutputFmt::CShell => result.push_str("setenv LS_COLORS '"),
+        _ => unreachable!(),
+    }
+
+    let mut table: HashMap<&str, &str> = HashMap::with_capacity(48);
+    table.insert("normal", "no");
+    table.insert("norm", "no");
+    table.insert("file", "fi");
+    table.insert("reset", "rs");
+    table.insert("dir", "di");
+    table.insert("lnk", "ln");
+    table.insert("link", "ln");
+    table.insert("symlink", "ln");
+    table.insert("orphan", "or");
+    table.insert("missing", "mi");
+    table.insert("fifo", "pi");
+    table.insert("pipe", "pi");
+    table.insert("sock", "so");
+    table.insert("blk", "bd");
+    table.insert("block", "bd");
+    table.insert("chr", "cd");
+    table.insert("char", "cd");
+    table.insert("door", "do");
+    table.insert("exec", "ex");
+    table.insert("left", "lc");
+    table.insert("leftcode", "lc");
+    table.insert("right", "rc");
+    table.insert("rightcode", "rc");
+    table.insert("end", "ec");
+    table.insert("endcode", "ec");
+    table.insert("suid", "su");
+    table.insert("setuid", "su");
+    table.insert("sgid", "sg");
+    table.insert("setgid", "sg");
+    table.insert("sticky", "st");
+    table.insert("other_writable", "ow");
+    table.insert("owr", "ow");
+    table.insert("sticky_other_writable", "tw");
+    table.insert("owt", "tw");
+    table.insert("capability", "ca");
+    table.insert("multihardlink", "mh");
+    table.insert("clrtoeol", "cl");
+
+    let term = env::var("TERM").unwrap_or_else(|_| "none".to_owned());
+    let term = term.as_str();
+
+    let mut state = ParseState::Global;
+
+    for (num, line) in lines.into_iter().enumerate() {
+        let num = num + 1;
+        let line = line.borrow().purify();
+        if line.is_empty() {
+            continue;
+        }
+
+        let (key, val) = line.split_two();
+        if val.is_empty() {
+            return Err(format!(
+                "{}:{}: invalid line;  missing second token",
+                fp, num
+            ));
+        }
+        let lower = key.to_lowercase();
+
+        if lower == "term" {
+            if term.fnmatch(val) {
+                state = ParseState::Matched;
+            } else if state != ParseState::Matched {
+                state = ParseState::Pass;
+            }
+        } else {
+            if state == ParseState::Matched {
+                // prevent subsequent mismatched TERM from
+                // cancelling the input
+                state = ParseState::Continue;
+            }
+            if state != ParseState::Pass {
+                if key.starts_with('.') {
+                    result.push_str(format!("*{}={}:", key, val).as_str());
+                } else if key.starts_with('*') {
+                    result.push_str(format!("{}={}:", key, val).as_str());
+                } else if lower == "options" || lower == "color" || lower == "eightbit" {
+                    // Slackware only. Ignore
+                } else if let Some(s) = table.get(lower.as_str()) {
+                    result.push_str(format!("{}={}:", s, val).as_str());
+                } else {
+                    return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key));
+                }
+            }
+        }
+    }
+
+    match fmt {
+        OutputFmt::Shell => result.push_str("';\nexport LS_COLORS"),
+        OutputFmt::CShell => result.push('\''),
+        _ => unreachable!(),
+    }
+
+    Ok(result)
+}
+
+
\ No newline at end of file diff --git a/src/uu_dirname/dirname.rs.html b/src/uu_dirname/dirname.rs.html new file mode 100644 index 000000000..49297e8e2 --- /dev/null +++ b/src/uu_dirname/dirname.rs.html @@ -0,0 +1,203 @@ +dirname.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Derek Chiang <derekchiang93@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::path::Path;
+use uucore::error::{UResult, UUsageError};
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "strip last component from file name";
+
+mod options {
+    pub const ZERO: &str = "zero";
+    pub const DIR: &str = "dir";
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION] NAME...", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    String::from(
+        "Output each NAME with its last non-slash component and trailing slashes
+        removed; if NAME contains no /'s, output '.' (meaning the current directory).",
+    )
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let usage = usage();
+    let after_help = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let separator = if matches.is_present(options::ZERO) {
+        "\0"
+    } else {
+        "\n"
+    };
+
+    let dirnames: Vec<String> = matches
+        .values_of(options::DIR)
+        .unwrap_or_default()
+        .map(str::to_owned)
+        .collect();
+
+    if !dirnames.is_empty() {
+        for path in dirnames.iter() {
+            let p = Path::new(path);
+            match p.parent() {
+                Some(d) => {
+                    if d.components().next() == None {
+                        print!(".")
+                    } else {
+                        print!("{}", d.to_string_lossy());
+                    }
+                }
+                None => {
+                    if p.is_absolute() || path == "/" {
+                        print!("/");
+                    } else {
+                        print!(".");
+                    }
+                }
+            }
+            print!("{}", separator);
+        }
+    } else {
+        return Err(UUsageError::new(1, "missing operand"));
+    }
+
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .about(ABOUT)
+        .version(crate_version!())
+        .arg(
+            Arg::with_name(options::ZERO)
+                .long(options::ZERO)
+                .short("z")
+                .help("separate output with NUL rather than newline"),
+        )
+        .arg(Arg::with_name(options::DIR).hidden(true).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_du/du.rs.html b/src/uu_du/du.rs.html new file mode 100644 index 000000000..3c26d8e64 --- /dev/null +++ b/src/uu_du/du.rs.html @@ -0,0 +1,1727 @@ +du.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Derek Chiang <derekchiang93@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use chrono::prelude::DateTime;
+use chrono::Local;
+use clap::ArgMatches;
+use clap::{crate_version, App, Arg};
+use std::collections::HashSet;
+use std::convert::TryFrom;
+use std::env;
+use std::fs;
+#[cfg(not(windows))]
+use std::fs::Metadata;
+use std::io::{stderr, ErrorKind, Result, Write};
+use std::iter;
+#[cfg(not(windows))]
+use std::os::unix::fs::MetadataExt;
+#[cfg(windows)]
+use std::os::windows::fs::MetadataExt;
+#[cfg(windows)]
+use std::os::windows::io::AsRawHandle;
+#[cfg(windows)]
+use std::path::Path;
+use std::path::PathBuf;
+use std::str::FromStr;
+use std::time::{Duration, UNIX_EPOCH};
+use std::{error::Error, fmt::Display};
+use uucore::error::{UError, UResult};
+use uucore::parse_size::{parse_size, ParseSizeError};
+use uucore::InvalidEncodingHandling;
+#[cfg(windows)]
+use winapi::shared::minwindef::{DWORD, LPVOID};
+#[cfg(windows)]
+use winapi::um::fileapi::{FILE_ID_INFO, FILE_STANDARD_INFO};
+#[cfg(windows)]
+use winapi::um::minwinbase::{FileIdInfo, FileStandardInfo};
+#[cfg(windows)]
+use winapi::um::winbase::GetFileInformationByHandleEx;
+#[cfg(windows)]
+use winapi::um::winnt::{FILE_ID_128, ULONGLONG};
+
+mod options {
+    pub const NULL: &str = "0";
+    pub const ALL: &str = "all";
+    pub const APPARENT_SIZE: &str = "apparent-size";
+    pub const BLOCK_SIZE: &str = "block-size";
+    pub const BYTES: &str = "b";
+    pub const TOTAL: &str = "c";
+    pub const MAX_DEPTH: &str = "d";
+    pub const HUMAN_READABLE: &str = "h";
+    pub const BLOCK_SIZE_1K: &str = "k";
+    pub const COUNT_LINKS: &str = "l";
+    pub const BLOCK_SIZE_1M: &str = "m";
+    pub const SEPARATE_DIRS: &str = "S";
+    pub const SUMMARIZE: &str = "s";
+    pub const THRESHOLD: &str = "threshold";
+    pub const SI: &str = "si";
+    pub const TIME: &str = "time";
+    pub const TIME_STYLE: &str = "time-style";
+    pub const ONE_FILE_SYSTEM: &str = "one-file-system";
+    pub const DEREFERENCE: &str = "dereference";
+    pub const INODES: &str = "inodes";
+    pub const FILE: &str = "FILE";
+}
+
+const SUMMARY: &str = "estimate file space usage";
+const LONG_HELP: &str = "
+Display values are in units of the first available SIZE from --block-size,
+and the DU_BLOCK_SIZE, BLOCK_SIZE and BLOCKSIZE environment variables.
+Otherwise, units default to 1024 bytes (or 512 if POSIXLY_CORRECT is set).
+
+SIZE is an integer and optional unit (example: 10M is 10*1024*1024).
+Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers
+of 1000).
+";
+
+// TODO: Support Z & Y (currently limited by size of u64)
+const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2), ('K', 1)];
+
+struct Options {
+    all: bool,
+    util_name: String,
+    max_depth: Option<usize>,
+    total: bool,
+    separate_dirs: bool,
+    one_file_system: bool,
+    dereference: bool,
+    inodes: bool,
+}
+
+#[derive(PartialEq, Eq, Hash, Clone, Copy)]
+struct FileInfo {
+    file_id: u128,
+    dev_id: u64,
+}
+
+struct Stat {
+    path: PathBuf,
+    is_dir: bool,
+    size: u64,
+    blocks: u64,
+    inodes: u64,
+    inode: Option<FileInfo>,
+    created: Option<u64>,
+    accessed: u64,
+    modified: u64,
+}
+
+impl Stat {
+    fn new(path: PathBuf, options: &Options) -> Result<Stat> {
+        let metadata = if options.dereference {
+            fs::metadata(&path)?
+        } else {
+            fs::symlink_metadata(&path)?
+        };
+
+        #[cfg(not(windows))]
+        let file_info = FileInfo {
+            file_id: metadata.ino() as u128,
+            dev_id: metadata.dev(),
+        };
+        #[cfg(not(windows))]
+        return Ok(Stat {
+            path,
+            is_dir: metadata.is_dir(),
+            size: metadata.len(),
+            blocks: metadata.blocks() as u64,
+            inodes: 1,
+            inode: Some(file_info),
+            created: birth_u64(&metadata),
+            accessed: metadata.atime() as u64,
+            modified: metadata.mtime() as u64,
+        });
+
+        #[cfg(windows)]
+        let size_on_disk = get_size_on_disk(&path);
+        #[cfg(windows)]
+        let file_info = get_file_info(&path);
+        #[cfg(windows)]
+        Ok(Stat {
+            path,
+            is_dir: metadata.is_dir(),
+            size: metadata.len(),
+            blocks: size_on_disk / 1024 * 2,
+            inode: file_info,
+            inodes: 1,
+            created: windows_creation_time_to_unix_time(metadata.creation_time()),
+            accessed: windows_time_to_unix_time(metadata.last_access_time()),
+            modified: windows_time_to_unix_time(metadata.last_write_time()),
+        })
+    }
+}
+
+#[cfg(windows)]
+// https://doc.rust-lang.org/std/os/windows/fs/trait.MetadataExt.html#tymethod.last_access_time
+// "The returned 64-bit value [...] which represents the number of 100-nanosecond intervals since January 1, 1601 (UTC)."
+// "If the underlying filesystem does not support last access time, the returned value is 0."
+fn windows_time_to_unix_time(win_time: u64) -> u64 {
+    (win_time / 10_000_000).saturating_sub(11_644_473_600)
+}
+
+#[cfg(windows)]
+fn windows_creation_time_to_unix_time(win_time: u64) -> Option<u64> {
+    (win_time / 10_000_000).checked_sub(11_644_473_600)
+}
+
+#[cfg(not(windows))]
+fn birth_u64(meta: &Metadata) -> Option<u64> {
+    meta.created()
+        .ok()
+        .and_then(|t| t.duration_since(UNIX_EPOCH).ok())
+        .map(|e| e.as_secs() as u64)
+}
+
+#[cfg(windows)]
+fn get_size_on_disk(path: &Path) -> u64 {
+    let mut size_on_disk = 0;
+
+    // bind file so it stays in scope until end of function
+    // if it goes out of scope the handle below becomes invalid
+    let file = match fs::File::open(path) {
+        Ok(file) => file,
+        Err(_) => return size_on_disk, // opening directories will fail
+    };
+
+    let handle = file.as_raw_handle();
+
+    unsafe {
+        let mut file_info: FILE_STANDARD_INFO = core::mem::zeroed();
+        let file_info_ptr: *mut FILE_STANDARD_INFO = &mut file_info;
+
+        let success = GetFileInformationByHandleEx(
+            handle,
+            FileStandardInfo,
+            file_info_ptr as LPVOID,
+            std::mem::size_of::<FILE_STANDARD_INFO>() as DWORD,
+        );
+
+        if success != 0 {
+            size_on_disk = *file_info.AllocationSize.QuadPart() as u64;
+        }
+    }
+
+    size_on_disk
+}
+
+#[cfg(windows)]
+fn get_file_info(path: &Path) -> Option<FileInfo> {
+    let mut result = None;
+
+    let file = match fs::File::open(path) {
+        Ok(file) => file,
+        Err(_) => return result,
+    };
+
+    let handle = file.as_raw_handle();
+
+    unsafe {
+        let mut file_info: FILE_ID_INFO = core::mem::zeroed();
+        let file_info_ptr: *mut FILE_ID_INFO = &mut file_info;
+
+        let success = GetFileInformationByHandleEx(
+            handle,
+            FileIdInfo,
+            file_info_ptr as LPVOID,
+            std::mem::size_of::<FILE_ID_INFO>() as DWORD,
+        );
+
+        if success != 0 {
+            result = Some(FileInfo {
+                file_id: std::mem::transmute::<FILE_ID_128, u128>(file_info.FileId),
+                dev_id: std::mem::transmute::<ULONGLONG, u64>(file_info.VolumeSerialNumber),
+            });
+        }
+    }
+
+    result
+}
+
+fn read_block_size(s: Option<&str>) -> usize {
+    if let Some(s) = s {
+        parse_size(s)
+            .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::BLOCK_SIZE)))
+    } else {
+        for env_var in &["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
+            if let Ok(env_size) = env::var(env_var) {
+                if let Ok(v) = parse_size(&env_size) {
+                    return v;
+                }
+            }
+        }
+        if env::var("POSIXLY_CORRECT").is_ok() {
+            512
+        } else {
+            1024
+        }
+    }
+}
+
+fn choose_size(matches: &ArgMatches, stat: &Stat) -> u64 {
+    if matches.is_present(options::INODES) {
+        stat.inodes
+    } else if matches.is_present(options::APPARENT_SIZE) || matches.is_present(options::BYTES) {
+        stat.size
+    } else {
+        // The st_blocks field indicates the number of blocks allocated to the file, 512-byte units.
+        // See: http://linux.die.net/man/2/stat
+        stat.blocks * 512
+    }
+}
+
+// this takes `my_stat` to avoid having to stat files multiple times.
+// XXX: this should use the impl Trait return type when it is stabilized
+fn du(
+    mut my_stat: Stat,
+    options: &Options,
+    depth: usize,
+    inodes: &mut HashSet<FileInfo>,
+) -> Box<dyn DoubleEndedIterator<Item = Stat>> {
+    let mut stats = vec![];
+    let mut futures = vec![];
+
+    if my_stat.is_dir {
+        let read = match fs::read_dir(&my_stat.path) {
+            Ok(read) => read,
+            Err(e) => {
+                safe_writeln!(
+                    stderr(),
+                    "{}: cannot read directory '{}': {}",
+                    options.util_name,
+                    my_stat.path.display(),
+                    e
+                );
+                return Box::new(iter::once(my_stat));
+            }
+        };
+
+        for f in read {
+            match f {
+                Ok(entry) => match Stat::new(entry.path(), options) {
+                    Ok(this_stat) => {
+                        if let Some(inode) = this_stat.inode {
+                            if inodes.contains(&inode) {
+                                continue;
+                            }
+                            inodes.insert(inode);
+                        }
+                        if this_stat.is_dir {
+                            if options.one_file_system {
+                                if let (Some(this_inode), Some(my_inode)) =
+                                    (this_stat.inode, my_stat.inode)
+                                {
+                                    if this_inode.dev_id != my_inode.dev_id {
+                                        continue;
+                                    }
+                                }
+                            }
+                            futures.push(du(this_stat, options, depth + 1, inodes));
+                        } else {
+                            my_stat.size += this_stat.size;
+                            my_stat.blocks += this_stat.blocks;
+                            my_stat.inodes += 1;
+                            if options.all {
+                                stats.push(this_stat);
+                            }
+                        }
+                    }
+                    Err(error) => match error.kind() {
+                        ErrorKind::PermissionDenied => {
+                            let description = format!("cannot access '{}'", entry.path().display());
+                            let error_message = "Permission denied";
+                            show_error_custom_description!(description, "{}", error_message)
+                        }
+                        _ => show_error!("cannot access '{}': {}", entry.path().display(), error),
+                    },
+                },
+                Err(error) => show_error!("{}", error),
+            }
+        }
+    }
+
+    stats.extend(futures.into_iter().flatten().filter(|stat| {
+        if !options.separate_dirs && stat.path.parent().unwrap() == my_stat.path {
+            my_stat.size += stat.size;
+            my_stat.blocks += stat.blocks;
+            my_stat.inodes += stat.inodes;
+        }
+        options
+            .max_depth
+            .map_or(true, |max_depth| depth < max_depth)
+    }));
+    stats.push(my_stat);
+    Box::new(stats.into_iter())
+}
+
+fn convert_size_human(size: u64, multiplier: u64, _block_size: u64) -> String {
+    for &(unit, power) in &UNITS {
+        let limit = multiplier.pow(power);
+        if size >= limit {
+            return format!("{:.1}{}", (size as f64) / (limit as f64), unit);
+        }
+    }
+    if size == 0 {
+        return "0".to_string();
+    }
+    format!("{}B", size)
+}
+
+fn convert_size_b(size: u64, _multiplier: u64, _block_size: u64) -> String {
+    format!("{}", ((size as f64) / (1_f64)).ceil())
+}
+
+fn convert_size_k(size: u64, multiplier: u64, _block_size: u64) -> String {
+    format!("{}", ((size as f64) / (multiplier as f64)).ceil())
+}
+
+fn convert_size_m(size: u64, multiplier: u64, _block_size: u64) -> String {
+    format!(
+        "{}",
+        ((size as f64) / ((multiplier * multiplier) as f64)).ceil()
+    )
+}
+
+fn convert_size_other(size: u64, _multiplier: u64, block_size: u64) -> String {
+    format!("{}", ((size as f64) / (block_size as f64)).ceil())
+}
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [FILE]...
+    {0} [OPTION]... --files0-from=F",
+        uucore::execution_phrase()
+    )
+}
+
+#[derive(Debug)]
+enum DuError {
+    InvalidMaxDepthArg(String),
+    SummarizeDepthConflict(String),
+    InvalidTimeStyleArg(String),
+    InvalidTimeArg(String),
+}
+
+impl Display for DuError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            DuError::InvalidMaxDepthArg(s) => write!(f, "invalid maximum depth '{}'", s),
+            DuError::SummarizeDepthConflict(s) => {
+                write!(f, "summarizing conflicts with --max-depth={}", s)
+            }
+            DuError::InvalidTimeStyleArg(s) => write!(
+                f,
+                "invalid argument '{}' for 'time style'
+Valid arguments are:
+- 'full-iso'
+- 'long-iso'
+- 'iso'
+Try '{} --help' for more information.",
+                s,
+                uucore::execution_phrase()
+            ),
+            DuError::InvalidTimeArg(s) => write!(
+                f,
+                "Invalid argument '{}' for --time.
+'birth' and 'creation' arguments are not supported on this platform.",
+                s
+            ),
+        }
+    }
+}
+
+impl Error for DuError {}
+
+impl UError for DuError {
+    fn code(&self) -> i32 {
+        match self {
+            Self::InvalidMaxDepthArg(_) => 1,
+            Self::SummarizeDepthConflict(_) => 1,
+            Self::InvalidTimeStyleArg(_) => 1,
+            Self::InvalidTimeArg(_) => 1,
+        }
+    }
+}
+
+#[uucore_procs::gen_uumain]
+#[allow(clippy::cognitive_complexity)]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let summarize = matches.is_present(options::SUMMARIZE);
+
+    let max_depth = parse_depth(matches.value_of(options::MAX_DEPTH), summarize)?;
+
+    let options = Options {
+        all: matches.is_present(options::ALL),
+        util_name: uucore::util_name(),
+        max_depth,
+        total: matches.is_present(options::TOTAL),
+        separate_dirs: matches.is_present(options::SEPARATE_DIRS),
+        one_file_system: matches.is_present(options::ONE_FILE_SYSTEM),
+        dereference: matches.is_present(options::DEREFERENCE),
+        inodes: matches.is_present(options::INODES),
+    };
+
+    let files = match matches.value_of(options::FILE) {
+        Some(_) => matches.values_of(options::FILE).unwrap().collect(),
+        None => vec!["."],
+    };
+
+    if options.inodes
+        && (matches.is_present(options::APPARENT_SIZE) || matches.is_present(options::BYTES))
+    {
+        show_warning!("options --apparent-size and -b are ineffective with --inodes")
+    }
+
+    let block_size = u64::try_from(read_block_size(matches.value_of(options::BLOCK_SIZE))).unwrap();
+
+    let threshold = matches.value_of(options::THRESHOLD).map(|s| {
+        Threshold::from_str(s)
+            .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::THRESHOLD)))
+    });
+
+    let multiplier: u64 = if matches.is_present(options::SI) {
+        1000
+    } else {
+        1024
+    };
+    let convert_size_fn = {
+        if matches.is_present(options::HUMAN_READABLE) || matches.is_present(options::SI) {
+            convert_size_human
+        } else if matches.is_present(options::BYTES) {
+            convert_size_b
+        } else if matches.is_present(options::BLOCK_SIZE_1K) {
+            convert_size_k
+        } else if matches.is_present(options::BLOCK_SIZE_1M) {
+            convert_size_m
+        } else {
+            convert_size_other
+        }
+    };
+    let convert_size = |size: u64| {
+        if options.inodes {
+            size.to_string()
+        } else {
+            convert_size_fn(size, multiplier, block_size)
+        }
+    };
+
+    let time_format_str = parse_time_style(matches.value_of("time-style"))?;
+
+    let line_separator = if matches.is_present(options::NULL) {
+        "\0"
+    } else {
+        "\n"
+    };
+
+    let mut grand_total = 0;
+    for path_string in files {
+        let path = PathBuf::from(&path_string);
+        match Stat::new(path, &options) {
+            Ok(stat) => {
+                let mut inodes: HashSet<FileInfo> = HashSet::new();
+                if let Some(inode) = stat.inode {
+                    inodes.insert(inode);
+                }
+                let iter = du(stat, &options, 0, &mut inodes);
+                let (_, len) = iter.size_hint();
+                let len = len.unwrap();
+                for (index, stat) in iter.enumerate() {
+                    let size = choose_size(&matches, &stat);
+
+                    if threshold.map_or(false, |threshold| threshold.should_exclude(size)) {
+                        continue;
+                    }
+
+                    if matches.is_present(options::TIME) {
+                        let tm = {
+                            let secs = {
+                                match matches.value_of(options::TIME) {
+                                    Some(s) => match s {
+                                        "ctime" | "status" => stat.modified,
+                                        "access" | "atime" | "use" => stat.accessed,
+                                        "birth" | "creation" => stat
+                                            .created
+                                            .ok_or_else(|| DuError::InvalidTimeArg(s.into()))?,
+                                        // below should never happen as clap already restricts the values.
+                                        _ => unreachable!("Invalid field for --time"),
+                                    },
+                                    None => stat.modified,
+                                }
+                            };
+                            DateTime::<Local>::from(UNIX_EPOCH + Duration::from_secs(secs))
+                        };
+                        if !summarize || index == len - 1 {
+                            let time_str = tm.format(time_format_str).to_string();
+                            print!(
+                                "{}\t{}\t{}{}",
+                                convert_size(size),
+                                time_str,
+                                stat.path.display(),
+                                line_separator
+                            );
+                        }
+                    } else if !summarize || index == len - 1 {
+                        print!(
+                            "{}\t{}{}",
+                            convert_size(size),
+                            stat.path.display(),
+                            line_separator
+                        );
+                    }
+                    if options.total && index == (len - 1) {
+                        // The last element will be the total size of the the path under
+                        // path_string.  We add it to the grand total.
+                        grand_total += size;
+                    }
+                }
+            }
+            Err(_) => {
+                show_error!("{}: {}", path_string, "No such file or directory");
+            }
+        }
+    }
+
+    if options.total {
+        print!("{}\ttotal", convert_size(grand_total));
+        print!("{}", line_separator);
+    }
+
+    Ok(())
+}
+
+fn parse_time_style(s: Option<&str>) -> UResult<&str> {
+    match s {
+        Some(s) => match s {
+            "full-iso" => Ok("%Y-%m-%d %H:%M:%S.%f %z"),
+            "long-iso" => Ok("%Y-%m-%d %H:%M"),
+            "iso" => Ok("%Y-%m-%d"),
+            _ => Err(DuError::InvalidTimeStyleArg(s.into()).into()),
+        },
+        None => Ok("%Y-%m-%d %H:%M"),
+    }
+}
+
+fn parse_depth(max_depth_str: Option<&str>, summarize: bool) -> UResult<Option<usize>> {
+    let max_depth = max_depth_str.as_ref().and_then(|s| s.parse::<usize>().ok());
+    match (max_depth_str, max_depth) {
+        (Some(s), _) if summarize => Err(DuError::SummarizeDepthConflict(s.into()).into()),
+        (Some(s), None) => Err(DuError::InvalidMaxDepthArg(s.into()).into()),
+        (Some(_), Some(_)) | (None, _) => Ok(max_depth),
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(SUMMARY)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::ALL)
+                .short("a")
+                .long(options::ALL)
+                .help("write counts for all files, not just directories"),
+        )
+        .arg(
+            Arg::with_name(options::APPARENT_SIZE)
+                .long(options::APPARENT_SIZE)
+                .help(
+                    "print apparent sizes,  rather  than  disk  usage \
+                    although  the apparent  size is usually smaller, it may be larger due to holes \
+                    in ('sparse') files, internal  fragmentation,  indirect  blocks, and the like"
+                )
+                .alias("app") // The GNU test suite uses this alias
+        )
+        .arg(
+            Arg::with_name(options::BLOCK_SIZE)
+                .short("B")
+                .long(options::BLOCK_SIZE)
+                .value_name("SIZE")
+                .help(
+                    "scale sizes  by  SIZE before printing them. \
+                    E.g., '-BM' prints sizes in units of 1,048,576 bytes.  See SIZE format below."
+                )
+        )
+        .arg(
+            Arg::with_name(options::BYTES)
+                .short("b")
+                .long("bytes")
+                .help("equivalent to '--apparent-size --block-size=1'")
+        )
+        .arg(
+            Arg::with_name(options::TOTAL)
+                .long("total")
+                .short("c")
+                .help("produce a grand total")
+        )
+        .arg(
+            Arg::with_name(options::MAX_DEPTH)
+                .short("d")
+                .long("max-depth")
+                .value_name("N")
+                .help(
+                    "print the total for a directory (or file, with --all) \
+                    only if it is N or fewer levels below the command \
+                    line argument;  --max-depth=0 is the same as --summarize"
+                )
+        )
+        .arg(
+            Arg::with_name(options::HUMAN_READABLE)
+                .long("human-readable")
+                .short("h")
+                .help("print sizes in human readable format (e.g., 1K 234M 2G)")
+        )
+        .arg(
+            Arg::with_name(options::INODES)
+                .long(options::INODES)
+                .help(
+                    "list inode usage information instead of block usage like --block-size=1K"
+                )
+        )
+        .arg(
+            Arg::with_name(options::BLOCK_SIZE_1K)
+                .short("k")
+                .help("like --block-size=1K")
+        )
+        .arg(
+            Arg::with_name(options::COUNT_LINKS)
+                .short("l")
+                .long("count-links")
+                .help("count sizes many times if hard linked")
+        )
+        .arg(
+            Arg::with_name(options::DEREFERENCE)
+                .short("L")
+                .long(options::DEREFERENCE)
+                .help("dereference all symbolic links")
+        )
+        // .arg(
+        //     Arg::with_name("no-dereference")
+        //         .short("P")
+        //         .long("no-dereference")
+        //         .help("don't follow any symbolic links (this is the default)")
+        // )
+        .arg(
+            Arg::with_name(options::BLOCK_SIZE_1M)
+                .short("m")
+                .help("like --block-size=1M")
+        )
+        .arg(
+            Arg::with_name(options::NULL)
+                .short("0")
+                .long("null")
+                .help("end each output line with 0 byte rather than newline")
+        )
+        .arg(
+            Arg::with_name(options::SEPARATE_DIRS)
+                .short("S")
+                .long("separate-dirs")
+                .help("do not include size of subdirectories")
+        )
+        .arg(
+            Arg::with_name(options::SUMMARIZE)
+                .short("s")
+                .long("summarize")
+                .help("display only a total for each argument")
+        )
+        .arg(
+            Arg::with_name(options::SI)
+                .long(options::SI)
+                .help("like -h, but use powers of 1000 not 1024")
+        )
+        .arg(
+            Arg::with_name(options::ONE_FILE_SYSTEM)
+                .short("x")
+                .long(options::ONE_FILE_SYSTEM)
+                .help("skip directories on different file systems")
+        )
+        .arg(
+            Arg::with_name(options::THRESHOLD)
+                .short("t")
+                .long(options::THRESHOLD)
+                .alias("th")
+                .value_name("SIZE")
+                .number_of_values(1)
+                .allow_hyphen_values(true)
+                .help("exclude entries smaller than SIZE if positive, \
+                          or entries greater than SIZE if negative")
+        )
+        // .arg(
+        //     Arg::with_name("")
+        //         .short("x")
+        //         .long("exclude-from")
+        //         .value_name("FILE")
+        //         .help("exclude files that match any pattern in FILE")
+        // )
+        // .arg(
+        //     Arg::with_name("exclude")
+        //         .long("exclude")
+        //         .value_name("PATTERN")
+        //         .help("exclude files that match PATTERN")
+        // )
+        .arg(
+            Arg::with_name(options::TIME)
+                .long(options::TIME)
+                .value_name("WORD")
+                .require_equals(true)
+                .min_values(0)
+                .possible_values(&["atime", "access", "use", "ctime", "status", "birth", "creation"])
+                .help(
+                    "show time of the last modification of any file in the \
+                    directory, or any of its subdirectories.  If WORD is given, show time as WORD instead \
+                    of modification time: atime, access, use, ctime, status, birth or creation"
+                )
+        )
+        .arg(
+            Arg::with_name(options::TIME_STYLE)
+                .long(options::TIME_STYLE)
+                .value_name("STYLE")
+                .help(
+                    "show times using style STYLE: \
+                    full-iso, long-iso, iso, +FORMAT FORMAT is interpreted like 'date'"
+                )
+        )
+        .arg(
+            Arg::with_name(options::FILE)
+                .hidden(true)
+                .multiple(true)
+        )
+}
+
+#[derive(Clone, Copy)]
+enum Threshold {
+    Lower(u64),
+    Upper(u64),
+}
+
+impl FromStr for Threshold {
+    type Err = ParseSizeError;
+
+    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
+        let offset = if s.starts_with(&['-', '+'][..]) { 1 } else { 0 };
+
+        let size = u64::try_from(parse_size(&s[offset..])?).unwrap();
+
+        if s.starts_with('-') {
+            Ok(Threshold::Upper(size))
+        } else {
+            Ok(Threshold::Lower(size))
+        }
+    }
+}
+
+impl Threshold {
+    fn should_exclude(&self, size: u64) -> bool {
+        match *self {
+            Threshold::Upper(threshold) => size > threshold,
+            Threshold::Lower(threshold) => size < threshold,
+        }
+    }
+}
+
+fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String {
+    // NOTE:
+    // GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection
+    // GNU's du does distinguish between "invalid (suffix in) argument"
+    match error {
+        ParseSizeError::ParseFailure(_) => format!("invalid --{} argument '{}'", option, s),
+        ParseSizeError::SizeTooBig(_) => format!("--{} argument '{}' too large", option, s),
+    }
+}
+
+#[cfg(test)]
+mod test_du {
+    #[allow(unused_imports)]
+    use super::*;
+
+    #[test]
+    fn test_read_block_size() {
+        let test_data = [
+            (Some("1024".to_string()), 1024),
+            (Some("K".to_string()), 1024),
+            (None, 1024),
+        ];
+        for it in test_data.iter() {
+            assert_eq!(read_block_size(it.0.as_deref()), it.1);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_echo/echo.rs.html b/src/uu_echo/echo.rs.html new file mode 100644 index 000000000..58f5e7688 --- /dev/null +++ b/src/uu_echo/echo.rs.html @@ -0,0 +1,399 @@ +echo.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Derek Chiang <derekchiang93@gmail.com>
+// (c) Christopher Brown <ccbrown112@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::io::{self, Write};
+use std::iter::Peekable;
+use std::str::Chars;
+use uucore::error::{FromIo, UResult};
+use uucore::InvalidEncodingHandling;
+
+const NAME: &str = "echo";
+const SUMMARY: &str = "display a line of text";
+const USAGE: &str = "[OPTIONS]... [STRING]...";
+const AFTER_HELP: &str = r#"
+ Echo the STRING(s) to standard output.
+
+ If -e is in effect, the following sequences are recognized:
+
+ \\\\      backslash
+ \\a      alert (BEL)
+ \\b      backspace
+ \\c      produce no further output
+ \\e      escape
+ \\f      form feed
+ \\n      new line
+ \\r      carriage return
+ \\t      horizontal tab
+ \\v      vertical tab
+ \\0NNN   byte with octal value NNN (1 to 3 digits)
+ \\xHH    byte with hexadecimal value HH (1 to 2 digits)
+"#;
+
+mod options {
+    pub const STRING: &str = "STRING";
+    pub const NO_NEWLINE: &str = "no_newline";
+    pub const ENABLE_BACKSLASH_ESCAPE: &str = "enable_backslash_escape";
+    pub const DISABLE_BACKSLASH_ESCAPE: &str = "disable_backslash_escape";
+}
+
+fn parse_code(
+    input: &mut Peekable<Chars>,
+    base: u32,
+    max_digits: u32,
+    bits_per_digit: u32,
+) -> Option<char> {
+    let mut ret = 0x8000_0000;
+    for _ in 0..max_digits {
+        match input.peek().and_then(|c| c.to_digit(base)) {
+            Some(n) => ret = (ret << bits_per_digit) | n,
+            None => break,
+        }
+        input.next();
+    }
+    std::char::from_u32(ret)
+}
+
+fn print_escaped(input: &str, mut output: impl Write) -> io::Result<bool> {
+    let mut should_stop = false;
+
+    let mut buffer = ['\\'; 2];
+
+    let mut iter = input.chars().peekable();
+    while let Some(mut c) = iter.next() {
+        let mut start = 1;
+
+        if c == '\\' {
+            if let Some(next) = iter.next() {
+                c = match next {
+                    '\\' => '\\',
+                    'a' => '\x07',
+                    'b' => '\x08',
+                    'c' => {
+                        should_stop = true;
+                        break;
+                    }
+                    'e' => '\x1b',
+                    'f' => '\x0c',
+                    'n' => '\n',
+                    'r' => '\r',
+                    't' => '\t',
+                    'v' => '\x0b',
+                    'x' => parse_code(&mut iter, 16, 2, 4).unwrap_or_else(|| {
+                        start = 0;
+                        next
+                    }),
+                    '0' => parse_code(&mut iter, 8, 3, 3).unwrap_or_else(|| {
+                        start = 0;
+                        next
+                    }),
+                    _ => {
+                        start = 0;
+                        next
+                    }
+                };
+            }
+        }
+
+        buffer[1] = c;
+
+        // because printing char slices is apparently not available in the standard library
+        for ch in &buffer[start..] {
+            write!(output, "{}", ch)?;
+        }
+    }
+
+    Ok(should_stop)
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+    let matches = uu_app().get_matches_from(args);
+
+    let no_newline = matches.is_present(options::NO_NEWLINE);
+    let escaped = matches.is_present(options::ENABLE_BACKSLASH_ESCAPE);
+    let values: Vec<String> = match matches.values_of(options::STRING) {
+        Some(s) => s.map(|s| s.to_string()).collect(),
+        None => vec!["".to_string()],
+    };
+
+    execute(no_newline, escaped, values).map_err_context(|| "could not write to stdout".to_string())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        // TrailingVarArg specifies the final positional argument is a VarArg
+        // and it doesn't attempts the parse any further args.
+        // Final argument must have multiple(true) or the usage string equivalent.
+        .setting(clap::AppSettings::TrailingVarArg)
+        .setting(clap::AppSettings::AllowLeadingHyphen)
+        .version(crate_version!())
+        .about(SUMMARY)
+        .after_help(AFTER_HELP)
+        .usage(USAGE)
+        .arg(
+            Arg::with_name(options::NO_NEWLINE)
+                .short("n")
+                .help("do not output the trailing newline")
+                .takes_value(false)
+                .display_order(1),
+        )
+        .arg(
+            Arg::with_name(options::ENABLE_BACKSLASH_ESCAPE)
+                .short("e")
+                .help("enable interpretation of backslash escapes")
+                .takes_value(false)
+                .display_order(2),
+        )
+        .arg(
+            Arg::with_name(options::DISABLE_BACKSLASH_ESCAPE)
+                .short("E")
+                .help("disable interpretation of backslash escapes (default)")
+                .takes_value(false)
+                .display_order(3),
+        )
+        .arg(
+            Arg::with_name(options::STRING)
+                .multiple(true)
+                .allow_hyphen_values(true),
+        )
+}
+
+fn execute(no_newline: bool, escaped: bool, free: Vec<String>) -> io::Result<()> {
+    let stdout = io::stdout();
+    let mut output = stdout.lock();
+
+    for (i, input) in free.iter().enumerate() {
+        if i > 0 {
+            write!(output, " ")?;
+        }
+        if escaped {
+            let should_stop = print_escaped(input, &mut output)?;
+            if should_stop {
+                break;
+            }
+        } else {
+            write!(output, "{}", input)?;
+        }
+    }
+
+    if !no_newline {
+        writeln!(output)?;
+    }
+
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_env/env.rs.html b/src/uu_env/env.rs.html new file mode 100644 index 000000000..b9ec1dfa9 --- /dev/null +++ b/src/uu_env/env.rs.html @@ -0,0 +1,553 @@ +env.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jordi Boggiano <j.boggiano@seld.be>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+/* last synced with: env (GNU coreutils) 8.13 */
+
+// spell-checker:ignore (ToDO) chdir execvp progname subcommand subcommands unsets
+
+#[macro_use]
+extern crate clap;
+
+use clap::{App, AppSettings, Arg};
+use ini::Ini;
+use std::borrow::Cow;
+use std::env;
+use std::io::{self, Write};
+use std::iter::Iterator;
+use std::process::Command;
+
+const USAGE: &str = "env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]";
+const AFTER_HELP: &str = "\
+A mere - implies -i. If no COMMAND, print the resulting environment.
+";
+
+struct Options<'a> {
+    ignore_env: bool,
+    null: bool,
+    running_directory: Option<&'a str>,
+    files: Vec<&'a str>,
+    unsets: Vec<&'a str>,
+    sets: Vec<(&'a str, &'a str)>,
+    program: Vec<&'a str>,
+}
+
+// print name=value env pairs on screen
+// if null is true, separate pairs with a \0, \n otherwise
+fn print_env(null: bool) {
+    let stdout_raw = io::stdout();
+    let mut stdout = stdout_raw.lock();
+    for (n, v) in env::vars() {
+        write!(stdout, "{}={}{}", n, v, if null { '\0' } else { '\n' }).unwrap();
+    }
+}
+
+fn parse_name_value_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<bool, i32> {
+    // is it a NAME=VALUE like opt ?
+    if let Some(idx) = opt.find('=') {
+        // yes, so push name, value pair
+        let (name, value) = opt.split_at(idx);
+        opts.sets.push((name, &value['='.len_utf8()..]));
+
+        Ok(false)
+    } else {
+        // no, it's a program-like opt
+        parse_program_opt(opts, opt).map(|_| true)
+    }
+}
+
+fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<(), i32> {
+    if opts.null {
+        eprintln!("{}: cannot specify --null (-0) with command", crate_name!());
+        eprintln!("Type \"{} --help\" for detailed information", crate_name!());
+        Err(1)
+    } else {
+        opts.program.push(opt);
+        Ok(())
+    }
+}
+
+fn load_config_file(opts: &mut Options) -> Result<(), i32> {
+    // NOTE: config files are parsed using an INI parser b/c it's available and compatible with ".env"-style files
+    //   ... * but support for actual INI files, although working, is not intended, nor claimed
+    for &file in &opts.files {
+        let conf = if file == "-" {
+            let stdin = io::stdin();
+            let mut stdin_locked = stdin.lock();
+            Ini::read_from(&mut stdin_locked)
+        } else {
+            Ini::load_from_file(file)
+        };
+
+        let conf = conf.map_err(|error| {
+            eprintln!("env: error: \"{}\": {}", file, error);
+            1
+        })?;
+
+        for (_, prop) in &conf {
+            // ignore all INI section lines (treat them as comments)
+            for (key, value) in prop.iter() {
+                env::set_var(key, value);
+            }
+        }
+    }
+
+    Ok(())
+}
+
+#[cfg(not(windows))]
+fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
+    let progname = Cow::from(args[0]);
+    (progname, &args[1..])
+}
+
+#[cfg(windows)]
+fn build_command<'a, 'b>(args: &'a mut Vec<&'b str>) -> (Cow<'b, str>, &'a [&'b str]) {
+    args.insert(0, "/d/c");
+    let progname = env::var("ComSpec")
+        .map(Cow::from)
+        .unwrap_or_else(|_| Cow::from("cmd"));
+
+    (progname, &args[..])
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(crate_name!())
+        .version(crate_version!())
+        .author(crate_authors!())
+        .about(crate_description!())
+        .usage(USAGE)
+        .after_help(AFTER_HELP)
+        .setting(AppSettings::AllowExternalSubcommands)
+        .arg(Arg::with_name("ignore-environment")
+            .short("i")
+            .long("ignore-environment")
+            .help("start with an empty environment"))
+        .arg(Arg::with_name("chdir")
+            .short("c")
+            .long("chdir")
+            .takes_value(true)
+            .number_of_values(1)
+            .value_name("DIR")
+            .help("change working directory to DIR"))
+        .arg(Arg::with_name("null")
+            .short("0")
+            .long("null")
+            .help("end each output line with a 0 byte rather than a newline (only valid when \
+                    printing the environment)"))
+        .arg(Arg::with_name("file")
+            .short("f")
+            .long("file")
+            .takes_value(true)
+            .number_of_values(1)
+            .value_name("PATH")
+            .multiple(true)
+            .help("read and set variables from a \".env\"-style configuration file (prior to any \
+                    unset and/or set)"))
+        .arg(Arg::with_name("unset")
+            .short("u")
+            .long("unset")
+            .takes_value(true)
+            .number_of_values(1)
+            .value_name("NAME")
+            .multiple(true)
+            .help("remove variable from the environment"))
+}
+
+fn run_env(args: impl uucore::Args) -> Result<(), i32> {
+    let app = uu_app();
+    let matches = app.get_matches_from(args);
+
+    let ignore_env = matches.is_present("ignore-environment");
+    let null = matches.is_present("null");
+    let running_directory = matches.value_of("chdir");
+    let files = matches
+        .values_of("file")
+        .map(Iterator::collect)
+        .unwrap_or_else(|| Vec::with_capacity(0));
+    let unsets = matches
+        .values_of("unset")
+        .map(Iterator::collect)
+        .unwrap_or_else(|| Vec::with_capacity(0));
+
+    let mut opts = Options {
+        ignore_env,
+        null,
+        running_directory,
+        files,
+        unsets,
+        sets: vec![],
+        program: vec![],
+    };
+
+    // change directory
+    if let Some(d) = opts.running_directory {
+        match env::set_current_dir(d) {
+            Ok(()) => d,
+            Err(error) => {
+                eprintln!("env: cannot change directory to \"{}\": {}", d, error);
+                return Err(125);
+            }
+        };
+    }
+
+    // we handle the name, value pairs and the program to be executed by treating them as external
+    // subcommands in clap
+    if let (external, Some(matches)) = matches.subcommand() {
+        let mut begin_prog_opts = false;
+
+        if external == "-" {
+            // "-" implies -i and stop parsing opts
+            opts.ignore_env = true;
+        } else {
+            begin_prog_opts = parse_name_value_opt(&mut opts, external)?;
+        }
+
+        if let Some(mut iter) = matches.values_of("") {
+            // read NAME=VALUE arguments (and up to a single program argument)
+            while !begin_prog_opts {
+                if let Some(opt) = iter.next() {
+                    begin_prog_opts = parse_name_value_opt(&mut opts, opt)?;
+                } else {
+                    break;
+                }
+            }
+
+            // read any leftover program arguments
+            for opt in iter {
+                parse_program_opt(&mut opts, opt)?;
+            }
+        }
+    }
+
+    // NOTE: we manually set and unset the env vars below rather than using Command::env() to more
+    //       easily handle the case where no command is given
+
+    // remove all env vars if told to ignore presets
+    if opts.ignore_env {
+        for (ref name, _) in env::vars() {
+            env::remove_var(name);
+        }
+    }
+
+    // load .env-style config file prior to those given on the command-line
+    load_config_file(&mut opts)?;
+
+    // unset specified env vars
+    for name in &opts.unsets {
+        env::remove_var(name);
+    }
+
+    // set specified env vars
+    for &(name, val) in &opts.sets {
+        // FIXME: set_var() panics if name is an empty string
+        env::set_var(name, val);
+    }
+
+    if !opts.program.is_empty() {
+        // we need to execute a command
+        let (prog, args) = build_command(&mut opts.program);
+
+        // FIXME: this should just use execvp() (no fork()) on Unix-like systems
+        match Command::new(&*prog).args(args).status() {
+            Ok(exit) if !exit.success() => return Err(exit.code().unwrap()),
+            Err(ref err) if err.kind() == io::ErrorKind::NotFound => return Err(127),
+            Err(_) => return Err(126),
+            Ok(_) => (),
+        }
+    } else {
+        // no program provided, so just dump all env vars to stdout
+        print_env(opts.null);
+    }
+
+    Ok(())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    match run_env(args) {
+        Ok(()) => 0,
+        Err(code) => code,
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_expand/expand.rs.html b/src/uu_expand/expand.rs.html new file mode 100644 index 000000000..386304a78 --- /dev/null +++ b/src/uu_expand/expand.rs.html @@ -0,0 +1,791 @@ +expand.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Virgile Andreani <virgile.andreani@anbuco.fr>
+// (c) kwantam <kwantam@gmail.com>
+//     * 2015-04-28 ~ updated to work with both UTF-8 and non-UTF-8 encodings
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) ctype cwidth iflag nbytes nspaces nums tspaces uflag
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use std::fs::File;
+use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
+use std::str::from_utf8;
+use unicode_width::UnicodeWidthChar;
+
+static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
+ With no FILE, or when FILE is -, read standard input.";
+
+pub mod options {
+    pub static TABS: &str = "tabs";
+    pub static INITIAL: &str = "initial";
+    pub static NO_UTF8: &str = "no-utf8";
+    pub static FILES: &str = "FILES";
+}
+
+static LONG_HELP: &str = "";
+
+static DEFAULT_TABSTOP: usize = 8;
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+/// The mode to use when replacing tabs beyond the last one specified in
+/// the `--tabs` argument.
+enum RemainingMode {
+    None,
+    Slash,
+    Plus,
+}
+
+/// Decide whether the character is either a space or a comma.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// assert!(is_space_or_comma(' '))
+/// assert!(is_space_or_comma(','))
+/// assert!(!is_space_or_comma('a'))
+/// ```
+fn is_space_or_comma(c: char) -> bool {
+    c == ' ' || c == ','
+}
+
+/// Parse a list of tabstops from a `--tabs` argument.
+///
+/// This function returns both the vector of numbers appearing in the
+/// comma- or space-separated list, and also an optional mode, specified
+/// by either a "/" or a "+" character appearing before the final number
+/// in the list. This mode defines the strategy to use for computing the
+/// number of spaces to use for columns beyond the end of the tab stop
+/// list specified here.
+fn tabstops_parse(s: String) -> (RemainingMode, Vec<usize>) {
+    // Leading commas and spaces are ignored.
+    let s = s.trim_start_matches(is_space_or_comma);
+
+    // If there were only commas and spaces in the string, just use the
+    // default tabstops.
+    if s.is_empty() {
+        return (RemainingMode::None, vec![DEFAULT_TABSTOP]);
+    }
+
+    let mut nums = vec![];
+    let mut remaining_mode = RemainingMode::None;
+    for word in s.split(is_space_or_comma) {
+        let bytes = word.as_bytes();
+        for i in 0..bytes.len() {
+            match bytes[i] {
+                b'+' => {
+                    remaining_mode = RemainingMode::Plus;
+                }
+                b'/' => {
+                    remaining_mode = RemainingMode::Slash;
+                }
+                _ => {
+                    // Parse a number from the byte sequence.
+                    let num = from_utf8(&bytes[i..]).unwrap().parse::<usize>().unwrap();
+
+                    // Tab size must be positive.
+                    if num == 0 {
+                        crash!(1, "{}\n", "tab size cannot be 0");
+                    }
+
+                    // Tab sizes must be ascending.
+                    if let Some(last_stop) = nums.last() {
+                        if *last_stop >= num {
+                            crash!(1, "tab sizes must be ascending");
+                        }
+                    }
+
+                    // Append this tab stop to the list of all tabstops.
+                    nums.push(num);
+                    break;
+                }
+            }
+        }
+    }
+    // If no numbers could be parsed (for example, if `s` were "+,+,+"),
+    // then just use the default tabstops.
+    if nums.is_empty() {
+        nums = vec![DEFAULT_TABSTOP];
+    }
+    (remaining_mode, nums)
+}
+
+struct Options {
+    files: Vec<String>,
+    tabstops: Vec<usize>,
+    tspaces: String,
+    iflag: bool,
+    uflag: bool,
+
+    /// Strategy for expanding tabs for columns beyond those specified
+    /// in `tabstops`.
+    remaining_mode: RemainingMode,
+}
+
+impl Options {
+    fn new(matches: &ArgMatches) -> Options {
+        let (remaining_mode, tabstops) = match matches.value_of(options::TABS) {
+            Some(s) => tabstops_parse(s.to_string()),
+            None => (RemainingMode::None, vec![DEFAULT_TABSTOP]),
+        };
+
+        let iflag = matches.is_present(options::INITIAL);
+        let uflag = !matches.is_present(options::NO_UTF8);
+
+        // avoid allocations when dumping out long sequences of spaces
+        // by precomputing the longest string of spaces we will ever need
+        let nspaces = tabstops
+            .iter()
+            .scan(0, |pr, &it| {
+                let ret = Some(it - *pr);
+                *pr = it;
+                ret
+            })
+            .max()
+            .unwrap(); // length of tabstops is guaranteed >= 1
+        let tspaces = " ".repeat(nspaces);
+
+        let files: Vec<String> = match matches.values_of(options::FILES) {
+            Some(s) => s.map(|v| v.to_string()).collect(),
+            None => vec!["-".to_owned()],
+        };
+
+        Options {
+            files,
+            tabstops,
+            tspaces,
+            iflag,
+            uflag,
+            remaining_mode,
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    expand(Options::new(&matches));
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::INITIAL)
+                .long(options::INITIAL)
+                .short("i")
+                .help("do not convert tabs after non blanks"),
+        )
+        .arg(
+            Arg::with_name(options::TABS)
+                .long(options::TABS)
+                .short("t")
+                .value_name("N, LIST")
+                .takes_value(true)
+                .help("have tabs N characters apart, not 8 or use comma separated list of explicit tab positions"),
+        )
+        .arg(
+            Arg::with_name(options::NO_UTF8)
+                .long(options::NO_UTF8)
+                .short("U")
+                .help("interpret input file as 8-bit ASCII rather than UTF-8"),
+        ).arg(
+            Arg::with_name(options::FILES)
+                .multiple(true)
+                .hidden(true)
+                .takes_value(true)
+        )
+}
+
+fn open(path: String) -> BufReader<Box<dyn Read + 'static>> {
+    let file_buf;
+    if path == "-" {
+        BufReader::new(Box::new(stdin()) as Box<dyn Read>)
+    } else {
+        file_buf = match File::open(&path[..]) {
+            Ok(a) => a,
+            Err(e) => crash!(1, "{}: {}\n", &path[..], e),
+        };
+        BufReader::new(Box::new(file_buf) as Box<dyn Read>)
+    }
+}
+
+/// Compute the number of spaces to the next tabstop.
+///
+/// `tabstops` is the sequence of tabstop locations.
+///
+/// `col` is the index of the current cursor in the line being written.
+///
+/// If `remaining_mode` is [`RemainingMode::Plus`], then the last entry
+/// in the `tabstops` slice is interpreted as a relative number of
+/// spaces, which this function will return for every input value of
+/// `col` beyond the end of the second-to-last element of `tabstops`.
+///
+/// If `remaining_mode` is [`RemainingMode::Plus`], then the last entry
+/// in the `tabstops` slice is interpreted as a relative number of
+/// spaces, which this function will return for every input value of
+/// `col` beyond the end of the second-to-last element of `tabstops`.
+fn next_tabstop(tabstops: &[usize], col: usize, remaining_mode: &RemainingMode) -> usize {
+    let num_tabstops = tabstops.len();
+    match remaining_mode {
+        RemainingMode::Plus => match tabstops[0..num_tabstops - 1].iter().find(|&&t| t > col) {
+            Some(t) => t - col,
+            None => tabstops[num_tabstops - 1] - 1,
+        },
+        RemainingMode::Slash => match tabstops[0..num_tabstops - 1].iter().find(|&&t| t > col) {
+            Some(t) => t - col,
+            None => tabstops[num_tabstops - 1] - col % tabstops[num_tabstops - 1],
+        },
+        RemainingMode::None => {
+            if num_tabstops == 1 {
+                tabstops[0] - col % tabstops[0]
+            } else {
+                match tabstops.iter().find(|&&t| t > col) {
+                    Some(t) => t - col,
+                    None => 1,
+                }
+            }
+        }
+    }
+}
+
+#[derive(PartialEq, Eq, Debug)]
+enum CharType {
+    Backspace,
+    Tab,
+    Other,
+}
+
+fn expand(options: Options) {
+    use self::CharType::*;
+
+    let mut output = BufWriter::new(stdout());
+    let ts = options.tabstops.as_ref();
+    let mut buf = Vec::new();
+
+    for file in options.files.into_iter() {
+        let mut fh = open(file);
+
+        while match fh.read_until(b'\n', &mut buf) {
+            Ok(s) => s > 0,
+            Err(_) => buf.is_empty(),
+        } {
+            let mut col = 0;
+            let mut byte = 0;
+            let mut init = true;
+
+            while byte < buf.len() {
+                let (ctype, cwidth, nbytes) = if options.uflag {
+                    let nbytes = char::from(buf[byte]).len_utf8();
+
+                    if byte + nbytes > buf.len() {
+                        // don't overrun buffer because of invalid UTF-8
+                        (Other, 1, 1)
+                    } else if let Ok(t) = from_utf8(&buf[byte..byte + nbytes]) {
+                        match t.chars().next() {
+                            Some('\t') => (Tab, 0, nbytes),
+                            Some('\x08') => (Backspace, 0, nbytes),
+                            Some(c) => (Other, UnicodeWidthChar::width(c).unwrap_or(0), nbytes),
+                            None => {
+                                // no valid char at start of t, so take 1 byte
+                                (Other, 1, 1)
+                            }
+                        }
+                    } else {
+                        (Other, 1, 1) // implicit assumption: non-UTF-8 char is 1 col wide
+                    }
+                } else {
+                    (
+                        match buf[byte] {
+                            // always take exactly 1 byte in strict ASCII mode
+                            0x09 => Tab,
+                            0x08 => Backspace,
+                            _ => Other,
+                        },
+                        1,
+                        1,
+                    )
+                };
+
+                // figure out how many columns this char takes up
+                match ctype {
+                    Tab => {
+                        // figure out how many spaces to the next tabstop
+                        let nts = next_tabstop(ts, col, &options.remaining_mode);
+                        col += nts;
+
+                        // now dump out either spaces if we're expanding, or a literal tab if we're not
+                        if init || !options.iflag {
+                            if nts <= options.tspaces.len() {
+                                safe_unwrap!(output.write_all(options.tspaces[..nts].as_bytes()));
+                            } else {
+                                safe_unwrap!(output.write_all(" ".repeat(nts).as_bytes()));
+                            };
+                        } else {
+                            safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
+                        }
+                    }
+                    _ => {
+                        col = if ctype == Other {
+                            col + cwidth
+                        } else if col > 0 {
+                            col - 1
+                        } else {
+                            0
+                        };
+
+                        // if we're writing anything other than a space, then we're
+                        // done with the line's leading spaces
+                        if buf[byte] != 0x20 {
+                            init = false;
+                        }
+
+                        safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
+                    }
+                }
+
+                byte += nbytes; // advance the pointer
+            }
+
+            safe_unwrap!(output.flush());
+            buf.truncate(0); // clear the buffer
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::next_tabstop;
+    use super::RemainingMode;
+
+    #[test]
+    fn test_next_tabstop_remaining_mode_none() {
+        assert_eq!(next_tabstop(&[1, 5], 0, &RemainingMode::None), 1);
+        assert_eq!(next_tabstop(&[1, 5], 3, &RemainingMode::None), 2);
+        assert_eq!(next_tabstop(&[1, 5], 6, &RemainingMode::None), 1);
+    }
+
+    #[test]
+    fn test_next_tabstop_remaining_mode_plus() {
+        assert_eq!(next_tabstop(&[1, 5], 0, &RemainingMode::Plus), 1);
+        assert_eq!(next_tabstop(&[1, 5], 3, &RemainingMode::Plus), 4);
+        assert_eq!(next_tabstop(&[1, 5], 6, &RemainingMode::Plus), 4);
+    }
+
+    #[test]
+    fn test_next_tabstop_remaining_mode_slash() {
+        assert_eq!(next_tabstop(&[1, 5], 0, &RemainingMode::Slash), 1);
+        assert_eq!(next_tabstop(&[1, 5], 3, &RemainingMode::Slash), 2);
+        assert_eq!(next_tabstop(&[1, 5], 6, &RemainingMode::Slash), 4);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_expr/expr.rs.html b/src/uu_expr/expr.rs.html new file mode 100644 index 000000000..52e2d76fd --- /dev/null +++ b/src/uu_expr/expr.rs.html @@ -0,0 +1,293 @@ +expr.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+
+//* This file is part of the uutils coreutils package.
+//*
+//* (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
+//*
+//* For the full copyright and license information, please view the LICENSE
+//* file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use uucore::InvalidEncodingHandling;
+
+mod syntax_tree;
+mod tokens;
+
+const VERSION: &str = "version";
+const HELP: &str = "help";
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .arg(Arg::with_name(VERSION).long(VERSION))
+        .arg(Arg::with_name(HELP).long(HELP))
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    // For expr utility we do not want getopts.
+    // The following usage should work without escaping hyphens: `expr -15 = 1 +  2 \* \( 3 - -4 \)`
+
+    if maybe_handle_help_or_version(&args) {
+        0
+    } else {
+        let token_strings = args[1..].to_vec();
+
+        match process_expr(&token_strings) {
+            Ok(expr_result) => print_expr_ok(&expr_result),
+            Err(expr_error) => print_expr_error(&expr_error),
+        }
+    }
+}
+
+fn process_expr(token_strings: &[String]) -> Result<String, String> {
+    let maybe_tokens = tokens::strings_to_tokens(token_strings);
+    let maybe_ast = syntax_tree::tokens_to_ast(maybe_tokens);
+    evaluate_ast(maybe_ast)
+}
+
+fn print_expr_ok(expr_result: &str) -> i32 {
+    println!("{}", expr_result);
+    if expr_result == "0" || expr_result.is_empty() {
+        1
+    } else {
+        0
+    }
+}
+
+fn print_expr_error(expr_error: &str) -> ! {
+    crash!(2, "{}", expr_error)
+}
+
+fn evaluate_ast(maybe_ast: Result<Box<syntax_tree::AstNode>, String>) -> Result<String, String> {
+    maybe_ast.and_then(|ast| ast.evaluate())
+}
+
+fn maybe_handle_help_or_version(args: &[String]) -> bool {
+    if args.len() == 2 {
+        if args[1] == "--help" {
+            print_help();
+            true
+        } else if args[1] == "--version" {
+            print_version();
+            true
+        } else {
+            false
+        }
+    } else {
+        false
+    }
+}
+
+fn print_help() {
+    //! The following is taken from GNU coreutils' "expr --help" output.
+    println!(
+        r#"Usage: expr EXPRESSION
+  or:  expr OPTION
+
+      --help       display this help and exit
+      --version    output version information and exit
+
+Print the value of EXPRESSION to standard output.  A blank line below
+separates increasing precedence groups.  EXPRESSION may be:
+
+  ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2
+
+  ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0
+
+  ARG1 < ARG2       ARG1 is less than ARG2
+  ARG1 <= ARG2      ARG1 is less than or equal to ARG2
+  ARG1 = ARG2       ARG1 is equal to ARG2
+  ARG1 != ARG2      ARG1 is unequal to ARG2
+  ARG1 >= ARG2      ARG1 is greater than or equal to ARG2
+  ARG1 > ARG2       ARG1 is greater than ARG2
+
+  ARG1 + ARG2       arithmetic sum of ARG1 and ARG2
+  ARG1 - ARG2       arithmetic difference of ARG1 and ARG2
+
+  ARG1 * ARG2       arithmetic product of ARG1 and ARG2
+  ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2
+  ARG1 % ARG2       arithmetic remainder of ARG1 divided by ARG2
+
+  STRING : REGEXP   anchored pattern match of REGEXP in STRING
+
+  match STRING REGEXP        same as STRING : REGEXP
+  substr STRING POS LENGTH   substring of STRING, POS counted from 1
+  index STRING CHARS         index in STRING where any CHARS is found, or 0
+  length STRING              length of STRING
+  + TOKEN                    interpret TOKEN as a string, even if it is a
+                               keyword like 'match' or an operator like '/'
+
+  ( EXPRESSION )             value of EXPRESSION
+
+Beware that many operators need to be escaped or quoted for shells.
+Comparisons are arithmetic if both ARGs are numbers, else lexicographical.
+Pattern matches return the string matched between \( and \) or null; if
+\( and \) are not used, they return the number of characters matched or 0.
+
+Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null
+or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.
+
+Environment variables:
+    * EXPR_DEBUG_TOKENS=1   dump expression's tokens
+    * EXPR_DEBUG_RPN=1      dump expression represented in reverse polish notation
+    * EXPR_DEBUG_SYA_STEP=1 dump each parser step
+    * EXPR_DEBUG_AST=1      dump expression represented abstract syntax tree"#
+    );
+}
+
+fn print_version() {
+    println!("{} {}", uucore::util_name(), crate_version!());
+}
+
+
\ No newline at end of file diff --git a/src/uu_expr/syntax_tree.rs.html b/src/uu_expr/syntax_tree.rs.html new file mode 100644 index 000000000..9921ab402 --- /dev/null +++ b/src/uu_expr/syntax_tree.rs.html @@ -0,0 +1,1079 @@ +syntax_tree.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+
+//* This file is part of the uutils coreutils package.
+//*
+//* (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
+//*
+//* For the full copyright and license information, please view the LICENSE
+//* file that was distributed with this source code.
+
+//!
+//! Here we employ shunting-yard algorithm for building AST from tokens according to operators' precedence and associative-ness.
+//! * https://en.wikipedia.org/wiki/Shunting-yard_algorithm
+//!
+
+// spell-checker:ignore (ToDO) binop binops ints paren prec
+
+use num_bigint::BigInt;
+use num_traits::{One, Zero};
+use onig::{Regex, RegexOptions, Syntax};
+
+use crate::tokens::Token;
+
+type TokenStack = Vec<(usize, Token)>;
+pub type OperandsList = Vec<Box<AstNode>>;
+
+#[derive(Debug)]
+pub enum AstNode {
+    Leaf {
+        token_idx: usize,
+        value: String,
+    },
+    Node {
+        token_idx: usize,
+        op_type: String,
+        operands: OperandsList,
+    },
+}
+impl AstNode {
+    fn debug_dump(&self) {
+        self.debug_dump_impl(1);
+    }
+    fn debug_dump_impl(&self, depth: usize) {
+        for _ in 0..depth {
+            print!("\t",);
+        }
+        match self {
+            AstNode::Leaf { token_idx, value } => println!(
+                "Leaf( {} ) at #{} ( evaluate -> {:?} )",
+                value,
+                token_idx,
+                self.evaluate()
+            ),
+            AstNode::Node {
+                token_idx,
+                op_type,
+                operands,
+            } => {
+                println!(
+                    "Node( {} ) at #{} (evaluate -> {:?})",
+                    op_type,
+                    token_idx,
+                    self.evaluate()
+                );
+                for operand in operands {
+                    operand.debug_dump_impl(depth + 1);
+                }
+            }
+        }
+    }
+
+    fn new_node(token_idx: usize, op_type: &str, operands: OperandsList) -> Box<AstNode> {
+        Box::new(AstNode::Node {
+            token_idx,
+            op_type: op_type.into(),
+            operands,
+        })
+    }
+    fn new_leaf(token_idx: usize, value: &str) -> Box<AstNode> {
+        Box::new(AstNode::Leaf {
+            token_idx,
+            value: value.into(),
+        })
+    }
+    pub fn evaluate(&self) -> Result<String, String> {
+        match self {
+            AstNode::Leaf { value, .. } => Ok(value.clone()),
+            AstNode::Node { op_type, .. } => match self.operand_values() {
+                Err(reason) => Err(reason),
+                Ok(operand_values) => match op_type.as_ref() {
+                    "+" => {
+                        infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a + b), &operand_values)
+                    }
+                    "-" => {
+                        infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a - b), &operand_values)
+                    }
+                    "*" => {
+                        infix_operator_two_ints(|a: BigInt, b: BigInt| Ok(a * b), &operand_values)
+                    }
+                    "/" => infix_operator_two_ints(
+                        |a: BigInt, b: BigInt| {
+                            if b.is_zero() {
+                                Err("division by zero".to_owned())
+                            } else {
+                                Ok(a / b)
+                            }
+                        },
+                        &operand_values,
+                    ),
+                    "%" => infix_operator_two_ints(
+                        |a: BigInt, b: BigInt| {
+                            if b.is_zero() {
+                                Err("division by zero".to_owned())
+                            } else {
+                                Ok(a % b)
+                            }
+                        },
+                        &operand_values,
+                    ),
+                    "=" => infix_operator_two_ints_or_two_strings(
+                        |a: BigInt, b: BigInt| Ok(bool_as_int(a == b)),
+                        |a: &String, b: &String| Ok(bool_as_string(a == b)),
+                        &operand_values,
+                    ),
+                    "!=" => infix_operator_two_ints_or_two_strings(
+                        |a: BigInt, b: BigInt| Ok(bool_as_int(a != b)),
+                        |a: &String, b: &String| Ok(bool_as_string(a != b)),
+                        &operand_values,
+                    ),
+                    "<" => infix_operator_two_ints_or_two_strings(
+                        |a: BigInt, b: BigInt| Ok(bool_as_int(a < b)),
+                        |a: &String, b: &String| Ok(bool_as_string(a < b)),
+                        &operand_values,
+                    ),
+                    ">" => infix_operator_two_ints_or_two_strings(
+                        |a: BigInt, b: BigInt| Ok(bool_as_int(a > b)),
+                        |a: &String, b: &String| Ok(bool_as_string(a > b)),
+                        &operand_values,
+                    ),
+                    "<=" => infix_operator_two_ints_or_two_strings(
+                        |a: BigInt, b: BigInt| Ok(bool_as_int(a <= b)),
+                        |a: &String, b: &String| Ok(bool_as_string(a <= b)),
+                        &operand_values,
+                    ),
+                    ">=" => infix_operator_two_ints_or_two_strings(
+                        |a: BigInt, b: BigInt| Ok(bool_as_int(a >= b)),
+                        |a: &String, b: &String| Ok(bool_as_string(a >= b)),
+                        &operand_values,
+                    ),
+                    "|" => Ok(infix_operator_or(&operand_values)),
+                    "&" => Ok(infix_operator_and(&operand_values)),
+                    ":" | "match" => operator_match(&operand_values),
+                    "length" => Ok(prefix_operator_length(&operand_values)),
+                    "index" => Ok(prefix_operator_index(&operand_values)),
+                    "substr" => Ok(prefix_operator_substr(&operand_values)),
+
+                    _ => Err(format!("operation not implemented: {}", op_type)),
+                },
+            },
+        }
+    }
+    pub fn operand_values(&self) -> Result<Vec<String>, String> {
+        if let AstNode::Node { operands, .. } = self {
+            let mut out = Vec::with_capacity(operands.len());
+            for operand in operands {
+                let value = operand.evaluate()?;
+                out.push(value);
+            }
+            Ok(out)
+        } else {
+            panic!("Invoked .operand_values(&self) not with ASTNode::Node")
+        }
+    }
+}
+
+pub fn tokens_to_ast(
+    maybe_tokens: Result<Vec<(usize, Token)>, String>,
+) -> Result<Box<AstNode>, String> {
+    maybe_tokens.and_then(|tokens| {
+        let mut out_stack: TokenStack = Vec::new();
+        let mut op_stack: TokenStack = Vec::new();
+
+        for (token_idx, token) in tokens {
+            push_token_to_either_stack(token_idx, &token, &mut out_stack, &mut op_stack)?;
+        }
+        move_rest_of_ops_to_out(&mut out_stack, &mut op_stack)?;
+        assert!(op_stack.is_empty());
+
+        maybe_dump_rpn(&out_stack);
+        let result = ast_from_rpn(&mut out_stack);
+        if !out_stack.is_empty() {
+            Err(
+                "syntax error (first RPN token does not represent the root of the expression AST)"
+                    .to_owned(),
+            )
+        } else {
+            maybe_dump_ast(&result);
+            result
+        }
+    })
+}
+
+fn maybe_dump_ast(result: &Result<Box<AstNode>, String>) {
+    use std::env;
+    if let Ok(debug_var) = env::var("EXPR_DEBUG_AST") {
+        if debug_var == "1" {
+            println!("EXPR_DEBUG_AST");
+            match result {
+                Ok(ast) => ast.debug_dump(),
+                Err(reason) => println!("\terr: {:?}", reason),
+            }
+        }
+    }
+}
+
+#[allow(clippy::ptr_arg)]
+fn maybe_dump_rpn(rpn: &TokenStack) {
+    use std::env;
+    if let Ok(debug_var) = env::var("EXPR_DEBUG_RPN") {
+        if debug_var == "1" {
+            println!("EXPR_DEBUG_RPN");
+            for token in rpn {
+                println!("\t{:?}", token);
+            }
+        }
+    }
+}
+
+fn ast_from_rpn(rpn: &mut TokenStack) -> Result<Box<AstNode>, String> {
+    match rpn.pop() {
+        None => Err("syntax error (premature end of expression)".to_owned()),
+
+        Some((token_idx, Token::Value { value })) => Ok(AstNode::new_leaf(token_idx, &value)),
+
+        Some((token_idx, Token::InfixOp { value, .. })) => {
+            maybe_ast_node(token_idx, &value, 2, rpn)
+        }
+
+        Some((token_idx, Token::PrefixOp { value, arity })) => {
+            maybe_ast_node(token_idx, &value, arity, rpn)
+        }
+
+        Some((token_idx, unexpected_token)) => {
+            panic!("unexpected token at #{} {:?}", token_idx, unexpected_token)
+        }
+    }
+}
+fn maybe_ast_node(
+    token_idx: usize,
+    op_type: &str,
+    arity: usize,
+    rpn: &mut TokenStack,
+) -> Result<Box<AstNode>, String> {
+    let mut operands = Vec::with_capacity(arity);
+    for _ in 0..arity {
+        let operand = ast_from_rpn(rpn)?;
+        operands.push(operand);
+    }
+    operands.reverse();
+    Ok(AstNode::new_node(token_idx, op_type, operands))
+}
+
+fn move_rest_of_ops_to_out(
+    out_stack: &mut TokenStack,
+    op_stack: &mut TokenStack,
+) -> Result<(), String> {
+    loop {
+        match op_stack.pop() {
+            None => return Ok(()),
+            Some((token_idx, Token::ParOpen)) => {
+                return Err(format!(
+                    "syntax error (Mismatched open-parenthesis at #{})",
+                    token_idx
+                ))
+            }
+            Some((token_idx, Token::ParClose)) => {
+                return Err(format!(
+                    "syntax error (Mismatched close-parenthesis at #{})",
+                    token_idx
+                ))
+            }
+            Some(other) => out_stack.push(other),
+        }
+    }
+}
+
+fn push_token_to_either_stack(
+    token_idx: usize,
+    token: &Token,
+    out_stack: &mut TokenStack,
+    op_stack: &mut TokenStack,
+) -> Result<(), String> {
+    let result = match token {
+        Token::Value { .. } => {
+            out_stack.push((token_idx, token.clone()));
+            Ok(())
+        }
+
+        Token::InfixOp { .. } => {
+            if op_stack.is_empty() {
+                op_stack.push((token_idx, token.clone()));
+                Ok(())
+            } else {
+                push_op_to_stack(token_idx, token, out_stack, op_stack)
+            }
+        }
+
+        Token::PrefixOp { .. } => {
+            op_stack.push((token_idx, token.clone()));
+            Ok(())
+        }
+
+        Token::ParOpen => {
+            op_stack.push((token_idx, token.clone()));
+            Ok(())
+        }
+
+        Token::ParClose => move_till_match_paren(out_stack, op_stack),
+    };
+    maybe_dump_shunting_yard_step(token_idx, token, out_stack, op_stack, &result);
+    result
+}
+
+#[allow(clippy::ptr_arg)]
+fn maybe_dump_shunting_yard_step(
+    token_idx: usize,
+    token: &Token,
+    out_stack: &TokenStack,
+    op_stack: &TokenStack,
+    result: &Result<(), String>,
+) {
+    use std::env;
+    if let Ok(debug_var) = env::var("EXPR_DEBUG_SYA_STEP") {
+        if debug_var == "1" {
+            println!("EXPR_DEBUG_SYA_STEP");
+            println!("\t{} => {:?}", token_idx, token);
+            println!("\t\tout: {:?}", out_stack);
+            println!("\t\top : {:?}", op_stack);
+            println!("\t\tresult: {:?}", result);
+        }
+    }
+}
+
+fn push_op_to_stack(
+    token_idx: usize,
+    token: &Token,
+    out_stack: &mut TokenStack,
+    op_stack: &mut TokenStack,
+) -> Result<(), String> {
+    if let Token::InfixOp {
+        precedence: prec,
+        left_assoc: la,
+        ..
+    } = *token
+    {
+        loop {
+            match op_stack.last() {
+                None => {
+                    op_stack.push((token_idx, token.clone()));
+                    return Ok(());
+                }
+
+                Some(&(_, Token::ParOpen)) => {
+                    op_stack.push((token_idx, token.clone()));
+                    return Ok(());
+                }
+
+                Some(&(
+                    _,
+                    Token::InfixOp {
+                        precedence: prev_prec,
+                        ..
+                    },
+                )) => {
+                    if la && prev_prec >= prec || !la && prev_prec > prec {
+                        out_stack.push(op_stack.pop().unwrap())
+                    } else {
+                        op_stack.push((token_idx, token.clone()));
+                        return Ok(());
+                    }
+                }
+
+                Some(&(_, Token::PrefixOp { .. })) => {
+                    op_stack.push((token_idx, token.clone()));
+                    return Ok(());
+                }
+
+                Some(_) => panic!("Non-operator on op_stack"),
+            }
+        }
+    } else {
+        panic!("Expected infix-op")
+    }
+}
+
+fn move_till_match_paren(
+    out_stack: &mut TokenStack,
+    op_stack: &mut TokenStack,
+) -> Result<(), String> {
+    loop {
+        let op = op_stack
+            .pop()
+            .ok_or_else(|| "syntax error (Mismatched close-parenthesis)".to_string())?;
+        match op {
+            (_, Token::ParOpen) => return Ok(()),
+            other => out_stack.push(other),
+        }
+    }
+}
+
+fn infix_operator_two_ints<F>(f: F, values: &[String]) -> Result<String, String>
+where
+    F: Fn(BigInt, BigInt) -> Result<BigInt, String>,
+{
+    assert!(values.len() == 2);
+    if let Ok(left) = values[0].parse::<BigInt>() {
+        if let Ok(right) = values[1].parse::<BigInt>() {
+            return f(left, right).map(|big_int| big_int.to_string());
+        }
+    }
+    Err("Expected an integer operand".to_string())
+}
+
+fn infix_operator_two_ints_or_two_strings<FI, FS>(
+    fi: FI,
+    fs: FS,
+    values: &[String],
+) -> Result<String, String>
+where
+    FI: Fn(BigInt, BigInt) -> Result<u8, String>,
+    FS: Fn(&String, &String) -> Result<String, String>,
+{
+    assert!(values.len() == 2);
+    if let (Some(a_int), Some(b_int)) = (
+        values[0].parse::<BigInt>().ok(),
+        values[1].parse::<BigInt>().ok(),
+    ) {
+        match fi(a_int, b_int) {
+            Ok(result) => Ok(result.to_string()),
+            Err(reason) => Err(reason),
+        }
+    } else {
+        fs(&values[0], &values[1])
+    }
+}
+
+fn infix_operator_or(values: &[String]) -> String {
+    assert!(values.len() == 2);
+    if value_as_bool(&values[0]) {
+        values[0].clone()
+    } else {
+        values[1].clone()
+    }
+}
+
+fn infix_operator_and(values: &[String]) -> String {
+    if value_as_bool(&values[0]) && value_as_bool(&values[1]) {
+        values[0].clone()
+    } else {
+        0.to_string()
+    }
+}
+
+fn operator_match(values: &[String]) -> Result<String, String> {
+    assert!(values.len() == 2);
+    let re = Regex::with_options(&values[1], RegexOptions::REGEX_OPTION_NONE, Syntax::grep())
+        .map_err(|err| err.description().to_string())?;
+    Ok(if re.captures_len() > 0 {
+        re.captures(&values[0])
+            .map(|captures| captures.at(1).unwrap())
+            .unwrap_or("")
+            .to_string()
+    } else {
+        re.find(&values[0])
+            .map_or("0".to_string(), |(start, end)| (end - start).to_string())
+    })
+}
+
+fn prefix_operator_length(values: &[String]) -> String {
+    assert!(values.len() == 1);
+    values[0].len().to_string()
+}
+
+fn prefix_operator_index(values: &[String]) -> String {
+    assert!(values.len() == 2);
+    let haystack = &values[0];
+    let needles = &values[1];
+
+    for (current_idx, ch_h) in haystack.chars().enumerate() {
+        for ch_n in needles.chars() {
+            if ch_n == ch_h {
+                return current_idx.to_string();
+            }
+        }
+    }
+    "0".to_string()
+}
+
+fn prefix_operator_substr(values: &[String]) -> String {
+    assert!(values.len() == 3);
+    let subj = &values[0];
+    let idx = match values[1]
+        .parse::<usize>()
+        .ok()
+        .and_then(|v| v.checked_sub(1))
+    {
+        Some(i) => i,
+        None => return String::new(),
+    };
+    let len = match values[2].parse::<usize>() {
+        Ok(i) => i,
+        Err(_) => return String::new(),
+    };
+
+    subj.chars().skip(idx).take(len).collect()
+}
+
+fn bool_as_int(b: bool) -> u8 {
+    if b {
+        1
+    } else {
+        0
+    }
+}
+fn bool_as_string(b: bool) -> String {
+    if b {
+        "1".to_string()
+    } else {
+        "0".to_string()
+    }
+}
+fn value_as_bool(s: &str) -> bool {
+    if s.is_empty() {
+        return false;
+    }
+    match s.parse::<BigInt>() {
+        Ok(n) => n.is_one(),
+        Err(_) => true,
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_expr/tokens.rs.html b/src/uu_expr/tokens.rs.html new file mode 100644 index 000000000..476143041 --- /dev/null +++ b/src/uu_expr/tokens.rs.html @@ -0,0 +1,329 @@ +tokens.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+
+//* This file is part of the uutils coreutils package.
+//*
+//* (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
+//*
+//* For the full copyright and license information, please view the LICENSE
+//* file that was distributed with this source code.
+
+//!
+//! The following tokens are present in the expr grammar:
+//! * integer literal;
+//! * string literal;
+//! * infix binary operators;
+//! * prefix operators.
+//!
+//! According to the man-page of expr we have expression split into tokens (each token -- separate CLI-argument).
+//! Hence all we need is to map the strings into the Token structures, except for some ugly fiddling with +-escaping.
+//!
+
+// spell-checker:ignore (ToDO) paren
+
+use num_bigint::BigInt;
+
+#[derive(Debug, Clone)]
+pub enum Token {
+    Value {
+        value: String,
+    },
+
+    ParOpen,
+    ParClose,
+
+    InfixOp {
+        precedence: u8,
+        left_assoc: bool,
+        value: String,
+    },
+
+    PrefixOp {
+        arity: usize,
+        value: String,
+    },
+}
+impl Token {
+    fn new_infix_op(v: &str, left_assoc: bool, precedence: u8) -> Self {
+        Token::InfixOp {
+            left_assoc,
+            precedence,
+            value: v.into(),
+        }
+    }
+    fn new_value(v: &str) -> Self {
+        Token::Value { value: v.into() }
+    }
+
+    fn is_infix_plus(&self) -> bool {
+        match self {
+            Token::InfixOp { value, .. } => value == "+",
+            _ => false,
+        }
+    }
+    fn is_a_number(&self) -> bool {
+        match self {
+            Token::Value { value, .. } => value.parse::<BigInt>().is_ok(),
+            _ => false,
+        }
+    }
+    fn is_a_close_paren(&self) -> bool {
+        matches!(*self, Token::ParClose)
+    }
+}
+
+pub fn strings_to_tokens(strings: &[String]) -> Result<Vec<(usize, Token)>, String> {
+    let mut tokens_acc = Vec::with_capacity(strings.len());
+    let mut tok_idx = 1;
+
+    for s in strings {
+        let token_if_not_escaped = match s.as_ref() {
+            "(" => Token::ParOpen,
+            ")" => Token::ParClose,
+
+            "^" => Token::new_infix_op(s, false, 7),
+
+            ":" => Token::new_infix_op(s, true, 6),
+
+            "*" => Token::new_infix_op(s, true, 5),
+            "/" => Token::new_infix_op(s, true, 5),
+            "%" => Token::new_infix_op(s, true, 5),
+
+            "+" => Token::new_infix_op(s, true, 4),
+            "-" => Token::new_infix_op(s, true, 4),
+
+            "=" => Token::new_infix_op(s, true, 3),
+            "!=" => Token::new_infix_op(s, true, 3),
+            "<" => Token::new_infix_op(s, true, 3),
+            ">" => Token::new_infix_op(s, true, 3),
+            "<=" => Token::new_infix_op(s, true, 3),
+            ">=" => Token::new_infix_op(s, true, 3),
+
+            "&" => Token::new_infix_op(s, true, 2),
+
+            "|" => Token::new_infix_op(s, true, 1),
+
+            "match" => Token::PrefixOp {
+                arity: 2,
+                value: s.clone(),
+            },
+            "substr" => Token::PrefixOp {
+                arity: 3,
+                value: s.clone(),
+            },
+            "index" => Token::PrefixOp {
+                arity: 2,
+                value: s.clone(),
+            },
+            "length" => Token::PrefixOp {
+                arity: 1,
+                value: s.clone(),
+            },
+
+            _ => Token::new_value(s),
+        };
+        push_token_if_not_escaped(&mut tokens_acc, tok_idx, token_if_not_escaped, s);
+        tok_idx += 1;
+    }
+    maybe_dump_tokens_acc(&tokens_acc);
+
+    Ok(tokens_acc)
+}
+
+fn maybe_dump_tokens_acc(tokens_acc: &[(usize, Token)]) {
+    use std::env;
+
+    if let Ok(debug_var) = env::var("EXPR_DEBUG_TOKENS") {
+        if debug_var == "1" {
+            println!("EXPR_DEBUG_TOKENS");
+            for token in tokens_acc {
+                println!("\t{:?}", token);
+            }
+        }
+    }
+}
+
+fn push_token_if_not_escaped(acc: &mut Vec<(usize, Token)>, tok_idx: usize, token: Token, s: &str) {
+    // Smells heuristics... :(
+    let prev_is_plus = match acc.last() {
+        None => false,
+        Some(t) => t.1.is_infix_plus(),
+    };
+    let should_use_as_escaped = if prev_is_plus && acc.len() >= 2 {
+        let pre_prev = &acc[acc.len() - 2];
+        !(pre_prev.1.is_a_number() || pre_prev.1.is_a_close_paren())
+    } else {
+        prev_is_plus
+    };
+
+    if should_use_as_escaped {
+        acc.pop();
+        acc.push((tok_idx, Token::new_value(s)))
+    } else {
+        acc.push((tok_idx, token))
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/cli.rs.html b/src/uu_factor/cli.rs.html new file mode 100644 index 000000000..cf0c2b3a6 --- /dev/null +++ b/src/uu_factor/cli.rs.html @@ -0,0 +1,169 @@ +cli.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2014 T. Jameson Little <t.jameson.little@gmail.com>
+// * (c) 2020 nicoo <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use std::error::Error;
+use std::fmt::Write as FmtWrite;
+use std::io::{self, stdin, stdout, BufRead, Write};
+
+mod factor;
+use clap::{crate_version, App, Arg};
+pub use factor::*;
+
+mod miller_rabin;
+pub mod numeric;
+mod rho;
+pub mod table;
+
+static SUMMARY: &str = "Print the prime factors of the given NUMBER(s).
+If none are specified, read from standard input.";
+
+mod options {
+    pub static NUMBER: &str = "NUMBER";
+}
+
+fn print_factors_str(
+    num_str: &str,
+    w: &mut io::BufWriter<impl io::Write>,
+    factors_buffer: &mut String,
+) -> Result<(), Box<dyn Error>> {
+    num_str.parse::<u64>().map_err(|e| e.into()).and_then(|x| {
+        factors_buffer.clear();
+        writeln!(factors_buffer, "{}:{}", x, factor(x))?;
+        w.write_all(factors_buffer.as_bytes())?;
+        Ok(())
+    })
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let matches = uu_app().get_matches_from(args);
+    let stdout = stdout();
+    // We use a smaller buffer here to pass a gnu test. 4KiB appears to be the default pipe size for bash.
+    let mut w = io::BufWriter::with_capacity(4 * 1024, stdout.lock());
+    let mut factors_buffer = String::new();
+
+    if let Some(values) = matches.values_of(options::NUMBER) {
+        for number in values {
+            if let Err(e) = print_factors_str(number, &mut w, &mut factors_buffer) {
+                show_warning!("{}: {}", number, e);
+            }
+        }
+    } else {
+        let stdin = stdin();
+
+        for line in stdin.lock().lines() {
+            for number in line.unwrap().split_whitespace() {
+                if let Err(e) = print_factors_str(number, &mut w, &mut factors_buffer) {
+                    show_warning!("{}: {}", number, e);
+                }
+            }
+        }
+    }
+
+    if let Err(e) = w.flush() {
+        show_error!("{}", e);
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(SUMMARY)
+        .arg(Arg::with_name(options::NUMBER).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/factor.rs.html b/src/uu_factor/factor.rs.html new file mode 100644 index 000000000..1eac80113 --- /dev/null +++ b/src/uu_factor/factor.rs.html @@ -0,0 +1,603 @@ +factor.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2020 nicoo <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+use smallvec::SmallVec;
+use std::cell::RefCell;
+use std::fmt;
+
+use crate::numeric::{Arithmetic, Montgomery};
+use crate::{miller_rabin, rho, table};
+
+type Exponent = u8;
+
+#[derive(Clone, Debug)]
+struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);
+
+// spell-checker:ignore (names) Erdős–Kac * Erdős Kac
+// The number of factors to inline directly into a `Decomposition` object.
+// As a consequence of the Erdős–Kac theorem, the average number of prime factors
+// of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use a slightly higher value.
+const NUM_FACTORS_INLINE: usize = 5;
+
+impl Decomposition {
+    fn one() -> Decomposition {
+        Decomposition(SmallVec::new())
+    }
+
+    fn add(&mut self, factor: u64, exp: Exponent) {
+        debug_assert!(exp > 0);
+
+        if let Some((_, e)) = self.0.iter_mut().find(|(f, _)| *f == factor) {
+            *e += exp;
+        } else {
+            self.0.push((factor, exp))
+        }
+    }
+
+    #[cfg(test)]
+    fn product(&self) -> u64 {
+        self.0
+            .iter()
+            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
+    }
+
+    fn get(&self, p: u64) -> Option<&(u64, u8)> {
+        self.0.iter().find(|(q, _)| *q == p)
+    }
+}
+
+impl PartialEq for Decomposition {
+    fn eq(&self, other: &Decomposition) -> bool {
+        for p in &self.0 {
+            if other.get(p.0) != Some(p) {
+                return false;
+            }
+        }
+
+        for p in &other.0 {
+            if self.get(p.0) != Some(p) {
+                return false;
+            }
+        }
+
+        true
+    }
+}
+impl Eq for Decomposition {}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct Factors(RefCell<Decomposition>);
+
+impl Factors {
+    pub fn one() -> Factors {
+        Factors(RefCell::new(Decomposition::one()))
+    }
+
+    pub fn add(&mut self, prime: u64, exp: Exponent) {
+        debug_assert!(miller_rabin::is_prime(prime));
+        self.0.borrow_mut().add(prime, exp)
+    }
+
+    pub fn push(&mut self, prime: u64) {
+        self.add(prime, 1)
+    }
+
+    #[cfg(test)]
+    fn product(&self) -> u64 {
+        self.0.borrow().product()
+    }
+}
+
+impl fmt::Display for Factors {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let v = &mut (self.0).borrow_mut().0;
+        v.sort_unstable();
+
+        for (p, exp) in v.iter() {
+            for _ in 0..*exp {
+                write!(f, " {}", p)?
+            }
+        }
+
+        Ok(())
+    }
+}
+
+fn _factor<A: Arithmetic + miller_rabin::Basis>(num: u64, f: Factors) -> Factors {
+    use miller_rabin::Result::*;
+
+    // Shadow the name, so the recursion automatically goes from “Big” arithmetic to small.
+    let _factor = |n, f| {
+        if n < (1 << 32) {
+            _factor::<Montgomery<u32>>(n, f)
+        } else {
+            _factor::<A>(n, f)
+        }
+    };
+
+    if num == 1 {
+        return f;
+    }
+
+    let n = A::new(num);
+    let divisor = match miller_rabin::test::<A>(n) {
+        Prime => {
+            #[cfg(feature = "coz")]
+            coz::progress!("factor found");
+            let mut r = f;
+            r.push(num);
+            return r;
+        }
+
+        Composite(d) => d,
+        Pseudoprime => rho::find_divisor::<A>(n),
+    };
+
+    let f = _factor(divisor, f);
+    _factor(num / divisor, f)
+}
+
+pub fn factor(mut n: u64) -> Factors {
+    #[cfg(feature = "coz")]
+    coz::begin!("factorization");
+    let mut factors = Factors::one();
+
+    if n < 2 {
+        return factors;
+    }
+
+    let n_zeros = n.trailing_zeros();
+    if n_zeros > 0 {
+        factors.add(2, n_zeros as Exponent);
+        n >>= n_zeros;
+    }
+
+    if n == 1 {
+        #[cfg(feature = "coz")]
+        coz::end!("factorization");
+        return factors;
+    }
+
+    table::factor(&mut n, &mut factors);
+
+    #[allow(clippy::let_and_return)]
+    let r = if n < (1 << 32) {
+        _factor::<Montgomery<u32>>(n, factors)
+    } else {
+        _factor::<Montgomery<u64>>(n, factors)
+    };
+
+    #[cfg(feature = "coz")]
+    coz::end!("factorization");
+
+    r
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{factor, Decomposition, Exponent, Factors};
+    use quickcheck::quickcheck;
+    use smallvec::smallvec;
+    use std::cell::RefCell;
+
+    #[test]
+    fn factor_2044854919485649() {
+        let f = Factors(RefCell::new(Decomposition(smallvec![
+            (503, 1),
+            (2423, 1),
+            (40961, 2)
+        ])));
+        assert_eq!(factor(f.product()), f);
+    }
+
+    #[test]
+    fn factor_recombines_small() {
+        assert!((1..10_000)
+            .map(|i| 2 * i + 1)
+            .all(|i| factor(i).product() == i));
+    }
+
+    #[test]
+    fn factor_recombines_overflowing() {
+        assert!((0..250)
+            .map(|i| 2 * i + 2u64.pow(32) + 1)
+            .all(|i| factor(i).product() == i));
+    }
+
+    #[test]
+    fn factor_recombines_strong_pseudoprime() {
+        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
+        //  and triggered a bug in rho::factor's code path handling
+        //  miller_rabbin::Result::Composite
+        let pseudoprime = 17179869183;
+        for _ in 0..20 {
+            // Repeat the test 20 times, as it only fails some fraction
+            // of the time.
+            assert!(factor(pseudoprime).product() == pseudoprime);
+        }
+    }
+
+    quickcheck! {
+        fn factor_recombines(i: u64) -> bool {
+            i == 0 || factor(i).product() == i
+        }
+
+        fn recombines_factors(f: Factors) -> () {
+            assert_eq!(factor(f.product()), f);
+        }
+
+        fn exponentiate_factors(f: Factors, e: Exponent) -> () {
+            if e == 0 { return; }
+            if let Some(fe) = f.product().checked_pow(e.into()) {
+                assert_eq!(factor(fe), f ^ e);
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+use rand::{
+    distributions::{Distribution, Standard},
+    Rng,
+};
+#[cfg(test)]
+impl Distribution<Factors> for Standard {
+    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Factors {
+        let mut f = Factors::one();
+        let mut g = 1u64;
+        let mut n = u64::MAX;
+
+        // spell-checker:ignore (names) Adam Kalai * Kalai's
+        // Adam Kalai's algorithm for generating uniformly-distributed
+        // integers and their factorization.
+        //
+        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
+        'attempt: loop {
+            while n > 1 {
+                n = rng.gen_range(1, n);
+                if miller_rabin::is_prime(n) {
+                    if let Some(h) = g.checked_mul(n) {
+                        f.push(n);
+                        g = h;
+                    } else {
+                        // We are overflowing u64, retry
+                        continue 'attempt;
+                    }
+                }
+            }
+
+            return f;
+        }
+    }
+}
+
+#[cfg(test)]
+impl quickcheck::Arbitrary for Factors {
+    fn arbitrary<G: quickcheck::Gen>(g: &mut G) -> Self {
+        g.gen()
+    }
+}
+
+#[cfg(test)]
+impl std::ops::BitXor<Exponent> for Factors {
+    type Output = Self;
+
+    fn bitxor(self, rhs: Exponent) -> Factors {
+        debug_assert_ne!(rhs, 0);
+        let mut r = Factors::one();
+        for (p, e) in self.0.borrow().0.iter() {
+            r.add(*p, rhs * e);
+        }
+
+        debug_assert_eq!(r.product(), self.product().pow(rhs.into()));
+        r
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/home/runner/work/coreutils-docs/coreutils-docs/coreutils/target/debug/build/uu_factor-4f609d691e1fa1f4/out/prime_table.rs.html b/src/uu_factor/home/runner/work/coreutils-docs/coreutils-docs/coreutils/target/debug/build/uu_factor-4f609d691e1fa1f4/out/prime_table.rs.html new file mode 100644 index 000000000..d14c7d524 --- /dev/null +++ b/src/uu_factor/home/runner/work/coreutils-docs/coreutils-docs/coreutils/target/debug/build/uu_factor-4f609d691e1fa1f4/out/prime_table.rs.html @@ -0,0 +1,363 @@ +prime_table.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+
+/*
+* This file is part of the uutils coreutils package.
+*
+* (c) kwantam <kwantam@gmail.com>
+*
+* For the full copyright and license information, please view the LICENSE file
+* that was distributed with this source code.
+*/
+
+// *** NOTE: this file was automatically generated.
+// Please do not edit by hand. Instead, modify and
+// re-run src/factor/gen_tables.rs.
+
+#[allow(clippy::unreadable_literal)]
+pub const PRIME_INVERSIONS_U64: &[(u64, u64, u64)] = &[
+    (3, 12297829382473034411, 6148914691236517205), (5, 14757395258967641293, 3689348814741910323),
+    (7, 7905747460161236407, 2635249153387078802), (11, 3353953467947191203, 1676976733973595601),
+    (13, 5675921253449092805, 1418980313362273201), (17, 17361641481138401521, 1085102592571150095),
+    (19, 9708812670373448219, 970881267037344821), (23, 15238614669586151335, 802032351030850070),
+    (29, 3816567739388183093, 636094623231363848), (31, 17256631552825064415, 595056260442243600),
+    (37, 1495681951922396077, 498560650640798692), (41, 10348173504763894809, 449920587163647600),
+    (43, 9437869060967677571, 428994048225803525), (47, 5887258746928580303, 392483916461905353),
+    (53, 2436362424829563421, 348051774975651917), (59, 14694863923124558067, 312656679215416129),
+    (61, 5745707170499696405, 302405640552615600), (67, 17345445920055250027, 275324538413575397),
+    (71, 1818693077689674103, 259813296812810586), (73, 9097024474706080249, 252695124297391118),
+    (79, 11208148297950107311, 233503089540627235), (83, 11779246215742243803, 222249928598910260),
+    (89, 17617676924329347049, 207266787345051141), (97, 11790702397628785569, 190172619316593315),
+    (101, 4200743699953660269, 182641030432767837), (103, 15760325033848937303, 179094602657374287),
+    (107, 8619973866219416643, 172399477324388332), (109, 12015769075535579493, 169236184162472950),
+    (113, 10447713457676206225, 163245522776190722), (127, 9150747060186627967, 145249953336295682),
+    (131, 281629680514649643, 140814840257324821), (137, 16292379802327414201, 134647766961383588),
+    (139, 4246732448623781667, 132710389019493177), (149, 16094474695182830269, 123803651501406386),
+    (151, 8062815290495565607, 122163868037811600), (157, 6579730370240349621, 117495185182863386),
+    (163, 2263404180823257867, 113170209041162893), (167, 10162278172342986519, 110459545351554201),
+    (173, 9809829218388894501, 106628578460748853), (179, 17107036403551874683, 103054436165975148),
+    (181, 3770881385233444253, 101915713114417412), (191, 2124755861893246783, 96579811904238490),
+    (193, 8124213711219232577, 95578984837873324), (197, 14513935692512591373, 93638294790403815),
+    (199, 2780916192016515319, 92697206400550510), (211, 13900627050804827995, 87425327363552377),
+    (223, 7527595115280579359, 82720825442643729), (227, 1950316554048586955, 81263189752024456),
+    (229, 2094390156840385773, 80553467570784068), (233, 7204522363551799129, 79170575423646144),
+    (239, 7255204782128442895, 77183029597111094), (241, 17298606475760824337, 76542506529915151),
+    (251, 2939720171109091891, 73493004277727297), (257, 18374966859414961921, 71777214294589695),
+    (263, 15430736487513693367, 70139711306880424), (269, 10354863773718001093, 68575256779589411),
+    (271, 15383631589145234927, 68069166323651481), (277, 17181443938689762877, 66594743948409933),
+    (281, 14245350405676059433, 65646776063023315), (283, 5149444458738708755, 65182841249857072),
+    (293, 2707201348701401773, 62958170900032599), (307, 17305088903023944187, 60087114246610917),
+    (311, 9134400602415662215, 59314289626075728), (313, 6365010734698503433, 58935284580541698),
+    (317, 17050145153302519317, 58191621683626345), (331, 3455281367280943203, 55730344633563600),
+    (337, 9196002980365592497, 54738112978366622), (347, 9941040754419844819, 53160645745560667),
+    (349, 15751088062938241781, 52856000211202153), (353, 8779186981255537313, 52257065364616293),
+    (359, 5600822016808749655, 51383688227603207), (367, 9751139919072624015, 50263607830271257),
+    (373, 3511310534137743069, 49455077945602015), (379, 17181268226964305331, 48672147951740241),
+    (383, 14834457375202459263, 48163822646761231), (389, 12661389891209383757, 47420935922132523),
+    (397, 185861401246443845, 46465350311610961), (401, 3220129888178724721, 46001855545410353),
+    (409, 2074694932495450793, 45102063749901104), (419, 1849076971589024267, 44025642180691053),
+    (421, 14897608040525528621, 43816494236839790), (431, 8046375605237577039, 42799870240625409),
+    (433, 7540585914657253201, 42602180308798040), (439, 15379290047785184263, 42019918163347497),
+    (443, 15615189678648040307, 41640505809728107), (449, 205420312624827969, 41084062524965593),
+    (457, 686202733595322489, 40364866682077793), (461, 3041111821262312197, 40014629227135686),
+    (463, 8127723090792113455, 39841779856824085), (467, 15247201739725667931, 39500522641776341),
+    (479, 8010277176057592351, 38510947961815347), (487, 2386334448960373207, 37878324586672590),
+    (491, 1051952818867347139, 37569743530976683), (499, 12494988971771199291, 36967422993405915),
+    (503, 17969989256695189447, 36673447462643243), (509, 5436172123882971989, 36241147492553146),
+    (521, 1805727346946616377, 35406418567580713), (523, 7195288319381928355, 35271021173440825),
+    (541, 13911777416032342069, 34097493666745936), (547, 13219604528142859659, 33723480939139948),
+    (557, 5133295029488295333, 33118032448311582), (563, 18151858289227516155, 32765087164670606),
+    (569, 6386658317259721737, 32419585366800617), (571, 1873749835858413299, 32306031652731263),
+    (577, 8184343991108570561, 31970093715267853), (587, 8107768264083584867, 31425458387920871),
+    (593, 13407330009728190129, 31107494222107169), (599, 16999336775772408167, 30795899956109435),
+    (601, 10926856722530117097, 30693417759916059), (607, 7810235958720518559, 30390023185682951),
+    (613, 10111102787547160429, 30092567820080834), (617, 5112468778937331161, 29897478239399597),
+    (619, 10400506755613301315, 29800878955912038), (631, 14909412801254946631, 29234142747558718),
+    (641, 18417966001831689601, 28778071877862015), (643, 12450835035754191915, 28688559990217032),
+    (647, 16650538700226241335, 28511196404496988), (653, 18023005695293558853, 28249225227732850),
+    (659, 13744083976011213723, 27992024391061535), (661, 3544230707051608253, 27907328401981167),
+    (673, 7016889276180750689, 27409723735081057), (677, 7711120491668837677, 27247775588935822),
+    (683, 18338710433453565955, 27008410063996415), (691, 16604739238563445883, 26695722248494285),
+    (701, 4578792394900801685, 26314898821268975), (709, 17796294705807240205, 26017974716092456),
+    (719, 7799457855921701935, 25656111368163493), (727, 3501582781529460967, 25373788271952615),
+    (733, 8027982755134170485, 25166090141486427), (739, 12755461734324196043, 24961764646426998),
+    (743, 8416482154761154775, 24827380987496031), (751, 73688724661955599, 24562908220651866),
+    (757, 11233750354002778461, 24368222026036395), (761, 8193166224591101769, 24240136759145271),
+    (769, 8635666926574042369, 23987963684927895), (773, 11955781087876436429, 23863834506739394),
+    (787, 1757948926973591323, 23439319026314550), (797, 3332912354597459765, 23145224684704581),
+    (809, 12062209660064712985, 22801908620160137), (811, 2229076349227541379, 22745677032934095),
+    (821, 4044353146489304861, 22468628591607249), (823, 5536264624794968711, 22414026821032261),
+    (827, 9502192231439261171, 22305615566758829), (829, 9813044796750195733, 22251802260204525),
+    (839, 17941052639030982263, 21986584116459537), (853, 13018686907823153661, 21625725760503577),
+    (857, 12247604875076703465, 21524788884141833), (859, 858986918449804499, 21474672961245112),
+    (863, 13637338028999645343, 21375137976488472), (877, 4964004106494246501, 21033915705484095),
+    (881, 14447506709261737361, 20938415520669184), (883, 17047047751015848379, 20890989890950794),
+    (887, 15763959422628906567, 20796780240935232), (907, 11979197639928253475, 20338196332645591),
+    (911, 16462352285319281519, 20248895799900715), (919, 16098246732442938407, 20072626848432591),
+    (929, 13264181960428396641, 19856559821000593), (937, 11792529028977610905, 19687026759561954),
+    (941, 1725094026021722149, 19603341204792297), (947, 18271431828024877947, 19479138409408185),
+    (953, 18137040080866579081, 19356499552685783), (967, 9614435380713147895, 19076260676018150),
+    (971, 10828675717831559651, 18997676697950104), (977, 12064963626510136625, 18881007240234955),
+    (983, 9326583728009813991, 18765762028188760), (991, 13160290676198438943, 18614272526447579),
+    (997, 11785933776281829869, 18502250826188115), (1009, 6965519813759503633, 18282204235589248),
+    (1013, 7775675932353384541, 18210013893099261), (1019, 10372899268140896051, 18102791043875909),
+    (1021, 7497942008412795221, 18067330140753723), (1031, 13544311604071901623, 17892089305246897),
+    (1033, 15464550210873641529, 17857448280454551), (1039, 1881958490676816623, 17754325383743553),
+    (1049, 8370495880920635433, 17585075380085368), (1051, 15691141010367591955, 17551611868420125),
+    (1061, 10466484384894580653, 17386186685871396), (1063, 5917535022704569239, 17353475139896097),
+    (1069, 13511506650808773541, 17256074905247475), (1087, 4836542834413267903, 16970325734783396),
+    (1091, 12613447368457676907, 16908106392034419), (1093, 12235946434985750157, 16877167496532069),
+    (1097, 14007418243755748857, 16815628143764404), (1103, 13546566364192871087, 16724156005176384),
+    (1109, 14687533829653321981, 16633673646266502), (1117, 17043007953507839989, 16514542590608372),
+    (1123, 10923494932339137867, 16426308168931034), (1129, 8610659102608444377, 16339011579902171),
+    (1151, 2852754513571068799, 16026710750399262), (1153, 16894849732729650049, 15998910731751562),
+    (1163, 14877941479913636643, 15861344861315177), (1171, 10554499171123313051, 15752983837497482),
+    (1181, 9918444103984390581, 15619597014148646), (1187, 6884505159775342347, 15540643701524474),
+    (1193, 17503532515875282841, 15462484554660143), (1201, 10275496907003905105, 15359487155461741),
+    (1213, 12439766407497455253, 15207538395473661), (1217, 6745111842892974913, 15157554703130280),
+    (1223, 5399782811437464823, 15083192210719175), (1229, 11572367518982965253, 15009555796346258),
+    (1231, 1168843247562424879, 14985169840543908), (1237, 12988774525627339901, 14912485104049758),
+    (1249, 2171073962238033697, 14769210627469616), (1259, 2754557494723904451, 14651901567680342),
+    (1277, 8710561218830743637, 14445375155606540), (1279, 10802667170608642815, 14422786609624356),
+    (1283, 17756608675784330667, 14377820790108769), (1289, 715544766241642809, 14310895324832856),
+    (1291, 10173572254439349923, 14288725076459761), (1297, 9401154844041645041, 14222624574949538),
+    (1301, 4069343235322552893, 14178896290322483), (1303, 17455744775812645543, 14157132827098658),
+    (1307, 11545093077501463827, 14113805718216948), (1319, 7286393982109686423, 13985401117293064),
+    (1321, 10375420777264342809, 13964227156479600), (1327, 17848997280062595535, 13901088224347815),
+    (1361, 8864195903163884465, 13553816365694012), (1367, 11915490136858474087, 13494326315808011),
+    (1373, 7241656996161287925, 13435356208091443), (1381, 10365440551193781357, 13357526483497140),
+    (1399, 11511084757933122631, 13185664098434275), (1409, 11062809611273648769, 13092082380205501),
+    (1423, 11991031811792927087, 12963277634370731), (1427, 10910337770294927515, 12926940486131430),
+    (1429, 4001742941112638909, 12908848197137544), (1433, 6539390083352723113, 12872815124710084),
+    (1439, 3589359513994909279, 12819141121410390), (1447, 15973580044476895767, 12748268191920906),
+    (1451, 6496406768894266627, 12713124792356686), (1453, 16301183338364118565, 12695625652931556),
+    (1459, 12921571242858918267, 12643416088903051), (1471, 15612641993044453951, 12540274693208396),
+    (1481, 7535638193514030201, 12455600319857901), (1483, 10846635760131307491, 12438802477214802),
+    (1487, 7517637463798243631, 12405342349502052), (1489, 9155234298503263025, 12388679700275051),
+    (1493, 17211195240909179773, 12355488328003718), (1499, 11419998999601376851, 12306033404742862),
+    (1511, 5310611298519956951, 12208301835678061), (1523, 3355054568888736571, 12112110356999048),
+    (1531, 13325995392242171187, 12048820426982071), (1543, 7651274275550300087, 11955116055547343),
+    (1549, 15826806245293734085, 11908808310980988), (1553, 14028077753413380849, 11878135269613362),
+    (1559, 9773579605442007463, 11832420829832938), (1567, 5579934072072959455, 11772012810280505),
+    (1571, 4004035473669609867, 11742039512227594), (1579, 17874299197451307139, 11682548495066213),
+    (1583, 11163601277709254863, 11653028473600474), (1597, 8663154699613126933, 11550872932817502),
+    (1601, 13918592655241185729, 11522013787451312), (1607, 1503748272343466871, 11478994445369976),
+    (1609, 4574425659049167865, 11464725962529242), (1613, 2904818967589724805, 11436295147991042),
+    (1619, 3999263230310100443, 11393912337065813), (1621, 9707015851248764669, 11379854456329149),
+    (1627, 10045368930120874451, 11337888182980670), (1637, 13127951646836669293, 11268628023035767),
+    (1657, 2237655738573095881, 11132615614791521), (1663, 5291098570751326591, 11092449833860223),
+    (1667, 12747839935760889899, 11065833277570216), (1669, 12312566146262696525, 11052572842246585),
+    (1693, 14633182097455361973, 10895891360726256), (1697, 3782832609104846177, 10870208646853006),
+    (1699, 15080946155610692875, 10857412639028576), (1709, 5137887758388383013, 10793881845353745),
+    (1721, 4062356771607158665, 10718619450150814), (1723, 2141235527998787187, 10706177639993935),
+    (1733, 18372233278258907149, 10644399350092066), (1741, 3401151549489239557, 10595487693112895),
+    (1747, 8806287668845887835, 10559097924275644), (1753, 5387754116223211881, 10522957258248460),
+    (1759, 4184338195230307615, 10487063145940620), (1777, 7816768873102584337, 10380835156842741),
+    (1783, 6114428349726497479, 10345902453005917), (1787, 17001559870956704819, 10322744305377477),
+    (1789, 18085851931406681685, 10311204065796283), (1801, 15916846357881534265, 10242500873797641),
+    (1811, 13751024019606788891, 10185943718227251), (1823, 16463440816196072671, 10118894170987137),
+    (1831, 11374316799136037015, 10074682727312698), (1847, 10307005892836089479, 9987408810887683),
+    (1861, 10526836220461872013, 9912275160510237), (1867, 12903828473628641891, 9880419964493600),
+    (1871, 5176130752911552431, 9859296672212480), (1873, 10567728986166763953, 9848768859428484),
+    (1877, 8451891264459357693, 9827780540069020), (1879, 13538084128603231335, 9817319890212640),
+    (1889, 13896091485912489121, 9765348900852065), (1901, 9383483176894863973, 9703705456975040),
+    (1907, 2843913349591299515, 9673174658473807), (1913, 12053544219622027977, 9642835375697622),
+    (1931, 10661090826649331747, 9552948769399042), (1933, 6680145293117788997, 9543064704453984),
+    (1949, 13790100623599187637, 9464722459573910), (1951, 7043989920509285471, 9455020027529242),
+    (1973, 17128451669050125981, 9349591522407274), (1979, 736378363730699635, 9321245110515185),
+    (1987, 11864589293508206827, 9283716192103448), (1993, 11727057070441546361, 9255767222132238),
+    (1997, 13994400236189269253, 9237227878672784), (1999, 2768395808960913199, 9227986029869710),
+    (2003, 16319336244939253851, 9209557700304319), (2011, 15043590393278798931, 9172920971511462),
+    (2017, 493864243916864545, 9145634146608602), (2027, 11384744369122175171, 9100515083231155),
+    (2029, 5309462069515218405, 9091544639580853), (2039, 9698337247188150727, 9046956387302379),
+    (2053, 11797649765601871053, 8985262578523892), (2063, 3818109413220542191, 8941708227682768),
+    (2069, 3798121302755084093, 8915777705997849), (2081, 15698790847928695777, 8864365244454373),
+    (2083, 13345772116697212811, 8855854092035310), (2087, 12993154666196952983, 8838880725304049),
+    (2089, 7205621428505023513, 8830418417285568), (2099, 9913257415504704251, 8788348772610553),
+    (2111, 6859637185154901951, 8738391318668664), (2113, 34920480972474305, 8730120243118576),
+    (2129, 5588609641870672049, 8664511072667708), (2131, 16317274790681607131, 8656379199300587),
+];
+
+#[allow(dead_code)]
+pub const NEXT_PRIME: u64 = 2137;
+
+
\ No newline at end of file diff --git a/src/uu_factor/miller_rabin.rs.html b/src/uu_factor/miller_rabin.rs.html new file mode 100644 index 000000000..c560b740a --- /dev/null +++ b/src/uu_factor/miller_rabin.rs.html @@ -0,0 +1,417 @@ +miller_rabin.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2020 nicoo <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+// spell-checker:ignore (URL) appspot
+
+use crate::numeric::*;
+
+pub(crate) trait Basis {
+    const BASIS: &'static [u64];
+}
+
+impl Basis for Montgomery<u64> {
+    // Small set of bases for the Miller-Rabin prime test, valid for all 64b integers;
+    //  discovered by Jim Sinclair on 2011-04-20, see miller-rabin.appspot.com
+    #[allow(clippy::unreadable_literal)]
+    const BASIS: &'static [u64] = &[2, 325, 9375, 28178, 450775, 9780504, 1795265022];
+}
+
+impl Basis for Montgomery<u32> {
+    // spell-checker:ignore (names) Steve Worley
+    // Small set of bases for the Miller-Rabin prime test, valid for all 32b integers;
+    //  discovered by Steve Worley on 2013-05-27, see miller-rabin.appspot.com
+    #[allow(clippy::unreadable_literal)]
+    const BASIS: &'static [u64] = &[
+        4230279247111683200,
+        14694767155120705706,
+        16641139526367750375,
+    ];
+}
+
+#[derive(Eq, PartialEq)]
+#[must_use = "Ignoring the output of a primality test."]
+pub(crate) enum Result {
+    Prime,
+    Pseudoprime,
+    Composite(u64),
+}
+
+impl Result {
+    pub(crate) fn is_prime(&self) -> bool {
+        *self == Result::Prime
+    }
+}
+
+// Deterministic Miller-Rabin primality-checking algorithm, adapted to extract
+// (some) dividers; it will fail to factor strong pseudoprimes.
+#[allow(clippy::many_single_char_names)]
+pub(crate) fn test<A: Arithmetic + Basis>(m: A) -> Result {
+    use self::Result::*;
+
+    let n = m.modulus();
+    debug_assert!(n > 1);
+    debug_assert!(n % 2 != 0);
+
+    // n-1 = r 2ⁱ
+    let i = (n - 1).trailing_zeros();
+    let r = (n - 1) >> i;
+
+    let one = m.one();
+    let minus_one = m.minus_one();
+
+    'witness: for _a in A::BASIS.iter() {
+        let _a = _a % n;
+        if _a == 0 {
+            continue;
+        }
+
+        let a = m.from_u64(_a);
+
+        // x = a^r mod n
+        let mut x = m.pow(a, r);
+
+        if x == one || x == minus_one {
+            continue;
+        }
+
+        for _ in 1..i {
+            let y = m.mul(x, x);
+            if y == one {
+                return Composite(gcd(m.to_u64(x) - 1, m.modulus()));
+            } else if y == minus_one {
+                // This basis element is not a witness of `n` being composite.
+                // Keep looking.
+                continue 'witness;
+            }
+            x = y;
+        }
+
+        return Pseudoprime;
+    }
+
+    Prime
+}
+
+// Used by build.rs' tests and debug assertions
+#[allow(dead_code)]
+pub(crate) fn is_prime(n: u64) -> bool {
+    if n < 2 {
+        false
+    } else if n % 2 == 0 {
+        n == 2
+    } else {
+        test::<Montgomery<u64>>(Montgomery::new(n)).is_prime()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::numeric::{traits::DoubleInt, Arithmetic, Montgomery};
+    use crate::parametrized_check;
+    use quickcheck::quickcheck;
+    use std::iter;
+    const LARGEST_U64_PRIME: u64 = 0xFFFFFFFFFFFFFFC5;
+
+    fn primes() -> impl Iterator<Item = u64> {
+        iter::once(2).chain(odd_primes())
+    }
+
+    fn odd_primes() -> impl Iterator<Item = u64> {
+        use crate::table::{NEXT_PRIME, PRIME_INVERSIONS_U64};
+        PRIME_INVERSIONS_U64
+            .iter()
+            .map(|(p, _, _)| *p)
+            .chain(iter::once(NEXT_PRIME))
+    }
+
+    #[test]
+    fn largest_prime() {
+        assert!(is_prime(LARGEST_U64_PRIME));
+    }
+
+    #[test]
+    fn largest_composites() {
+        for i in LARGEST_U64_PRIME + 1..=u64::MAX {
+            assert!(!is_prime(i), "2⁶⁴ - {} reported prime", u64::MAX - i + 1);
+        }
+    }
+
+    #[test]
+    fn two() {
+        assert!(is_prime(2));
+    }
+
+    fn first_primes<A: DoubleInt>()
+    where
+        Montgomery<A>: Basis,
+    {
+        for p in odd_primes() {
+            assert!(
+                test(Montgomery::<A>::new(p)).is_prime(),
+                "{} reported composite",
+                p
+            );
+        }
+    }
+    parametrized_check!(first_primes);
+
+    #[test]
+    fn one() {
+        assert!(!is_prime(1));
+    }
+    #[test]
+    fn zero() {
+        assert!(!is_prime(0));
+    }
+
+    #[test]
+    fn first_composites() {
+        for (p, q) in primes().zip(odd_primes()) {
+            for i in p + 1..q {
+                assert!(!is_prime(i), "{} reported prime", i);
+            }
+        }
+    }
+
+    #[test]
+    fn issue_1556() {
+        // 10 425 511 = 2441 × 4271
+        assert!(!is_prime(10_425_511));
+    }
+
+    fn small_semiprimes<A: DoubleInt>()
+    where
+        Montgomery<A>: Basis,
+    {
+        for p in odd_primes() {
+            for q in odd_primes().take_while(|q| *q <= p) {
+                let n = p * q;
+                let m = Montgomery::<A>::new(n);
+                assert!(!test(m).is_prime(), "{} = {} × {} reported prime", n, p, q);
+            }
+        }
+    }
+    parametrized_check!(small_semiprimes);
+
+    quickcheck! {
+        fn composites(i: u64, j: u64) -> bool {
+            i < 2 || j < 2 || !is_prime(i*j)
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/numeric/gcd.rs.html b/src/uu_factor/numeric/gcd.rs.html new file mode 100644 index 000000000..ca35c8035 --- /dev/null +++ b/src/uu_factor/numeric/gcd.rs.html @@ -0,0 +1,223 @@ +gcd.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
+// * (c) 2020 nicoo            <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+use std::cmp::min;
+use std::mem::swap;
+
+pub fn gcd(mut u: u64, mut v: u64) -> u64 {
+    // Stein's binary GCD algorithm
+    // Base cases: gcd(n, 0) = gcd(0, n) = n
+    if u == 0 {
+        return v;
+    } else if v == 0 {
+        return u;
+    }
+
+    // gcd(2ⁱ u, 2ʲ v) = 2ᵏ gcd(u, v) with u, v odd and k = min(i, j)
+    // 2ᵏ is the greatest power of two that divides both u and v
+    let k = {
+        let i = u.trailing_zeros();
+        let j = v.trailing_zeros();
+        u >>= i;
+        v >>= j;
+        min(i, j)
+    };
+
+    loop {
+        // Loop invariant: u and v are odd
+        debug_assert!(u % 2 == 1, "u = {} is even", u);
+        debug_assert!(v % 2 == 1, "v = {} is even", v);
+
+        // gcd(u, v) = gcd(|u - v|, min(u, v))
+        if u > v {
+            swap(&mut u, &mut v);
+        }
+        v -= u;
+
+        if v == 0 {
+            // Reached the base case; gcd is 2ᵏ u
+            return u << k;
+        }
+
+        // gcd(u, 2ʲ v) = gcd(u, v) as u is odd
+        v >>= v.trailing_zeros();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use quickcheck::quickcheck;
+
+    quickcheck! {
+        fn euclidean(a: u64, b: u64) -> bool {
+            // Test against the Euclidean algorithm
+            let g = {
+                let (mut a, mut b) = (a, b);
+                while b > 0 {
+                    a %= b;
+                    swap(&mut a, &mut b);
+                }
+                a
+            };
+            gcd(a, b) == g
+        }
+
+        fn one(a: u64) -> bool {
+            gcd(1, a) == 1
+        }
+
+        fn zero(a: u64) -> bool {
+            gcd(0, a) == a
+        }
+
+        fn divisor(a: u64, b: u64) -> () {
+            // Test that gcd(a, b) divides a and b, unless a == b == 0
+            if a == 0 && b == 0 { return; }
+
+            let g = gcd(a, b);
+            assert_eq!(a % g, 0);
+            assert_eq!(b % g, 0);
+        }
+
+        fn commutative(a: u64, b: u64) -> bool {
+            gcd(a, b) == gcd(b, a)
+        }
+
+        fn associative(a: u64, b: u64, c: u64) -> bool {
+            gcd(a, gcd(b, c)) == gcd(gcd(a, b), c)
+        }
+
+        fn scalar_multiplication(a: u64, b: u64, k: u64) -> bool {
+            gcd(k * a, k * b) == k * gcd(a, b)
+        }
+
+        fn multiplicative(a: u64, b: u64, c: u64) -> bool {
+            // gcd(ab, c) = gcd(a, c) gcd(b, c) when a and b coprime
+            gcd(a, b) != 1 || gcd(a * b, c) == gcd(a, c) * gcd(b, c)
+        }
+
+        fn linearity(a: u64, b: u64, k: u64) -> bool {
+            gcd(a + k * b, b) == gcd(a, b)
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/numeric/mod.rs.html b/src/uu_factor/numeric/mod.rs.html new file mode 100644 index 000000000..f18fda464 --- /dev/null +++ b/src/uu_factor/numeric/mod.rs.html @@ -0,0 +1,39 @@ +mod.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2020 nicoo            <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+mod gcd;
+pub use gcd::gcd;
+
+pub(crate) mod traits;
+
+mod modular_inverse;
+pub(crate) use modular_inverse::modular_inverse;
+
+mod montgomery;
+pub(crate) use montgomery::{Arithmetic, Montgomery};
+
+
\ No newline at end of file diff --git a/src/uu_factor/numeric/modular_inverse.rs.html b/src/uu_factor/numeric/modular_inverse.rs.html new file mode 100644 index 000000000..577149f7b --- /dev/null +++ b/src/uu_factor/numeric/modular_inverse.rs.html @@ -0,0 +1,155 @@ +modular_inverse.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
+// * (c) 2020 nicoo            <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+use super::traits::Int;
+
+// extended Euclid algorithm
+// precondition: a is odd
+pub(crate) fn modular_inverse<T: Int>(a: T) -> T {
+    let zero = T::zero();
+    let one = T::one();
+    debug_assert!(a % (one + one) == one, "{:?} is not odd", a);
+
+    let mut t = zero;
+    let mut new_t = one;
+    let mut r = zero;
+    let mut new_r = a;
+
+    while new_r != zero {
+        let quot = if r == zero {
+            // special case when we're just starting out
+            // This works because we know that
+            // a does not divide 2^64, so floor(2^64 / a) == floor((2^64-1) / a);
+            T::max_value()
+        } else {
+            r
+        } / new_r;
+
+        let new_tp = t.wrapping_sub(&quot.wrapping_mul(&new_t));
+        t = new_t;
+        new_t = new_tp;
+
+        let new_rp = r.wrapping_sub(&quot.wrapping_mul(&new_r));
+        r = new_r;
+        new_r = new_rp;
+    }
+
+    debug_assert_eq!(r, one);
+    t
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{super::traits::Int, *};
+    use crate::parametrized_check;
+    use quickcheck::quickcheck;
+
+    fn small_values<T: Int>() {
+        // All odd integers from 1 to 20 000
+        let one = T::from(1).unwrap();
+        let two = T::from(2).unwrap();
+        let mut test_values = (0..10_000)
+            .map(|i| T::from(i).unwrap())
+            .map(|i| two * i + one);
+
+        assert!(test_values.all(|x| x.wrapping_mul(&modular_inverse(x)) == one));
+    }
+    parametrized_check!(small_values);
+
+    quickcheck! {
+        fn random_values_u32(n: u32) -> bool {
+            let n = 2 * n + 1;
+            modular_inverse(n).wrapping_mul(n) == 1
+        }
+
+        fn random_values_u64(n: u64) -> bool {
+            let n = 2 * n + 1;
+            modular_inverse(n).wrapping_mul(n) == 1
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/numeric/montgomery.rs.html b/src/uu_factor/numeric/montgomery.rs.html new file mode 100644 index 000000000..9bc45680f --- /dev/null +++ b/src/uu_factor/numeric/montgomery.rs.html @@ -0,0 +1,463 @@ +montgomery.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2020 Alex Lyon  <arcterus@mail.com>
+// * (c) 2020 nicoo      <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+use super::*;
+
+use traits::{DoubleInt, Int, One, OverflowingAdd, Zero};
+
+pub(crate) trait Arithmetic: Copy + Sized {
+    // The type of integers mod m, in some opaque representation
+    type ModInt: Copy + Sized + Eq;
+
+    fn new(m: u64) -> Self;
+    fn modulus(&self) -> u64;
+    fn from_u64(&self, n: u64) -> Self::ModInt;
+    fn to_u64(&self, n: Self::ModInt) -> u64;
+    fn add(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
+    fn mul(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt;
+
+    fn pow(&self, mut a: Self::ModInt, mut b: u64) -> Self::ModInt {
+        let (_a, _b) = (a, b);
+        let mut result = self.one();
+        while b > 0 {
+            if b & 1 != 0 {
+                result = self.mul(result, a);
+            }
+            a = self.mul(a, a);
+            b >>= 1;
+        }
+
+        // Check that r (reduced back to the usual representation) equals
+        //  a^b % n, unless the latter computation overflows
+        // Temporarily commented-out, as there u64::checked_pow is not available
+        //  on the minimum supported Rust version, nor is an appropriate method
+        //  for compiling the check conditionally.
+        //debug_assert!(self
+        //    .to_u64(_a)
+        //    .checked_pow(_b as u32)
+        //    .map(|r| r % self.modulus() == self.to_u64(result))
+        //    .unwrap_or(true));
+
+        result
+    }
+
+    fn one(&self) -> Self::ModInt {
+        self.from_u64(1)
+    }
+    fn minus_one(&self) -> Self::ModInt {
+        self.from_u64(self.modulus() - 1)
+    }
+    fn zero(&self) -> Self::ModInt {
+        self.from_u64(0)
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub(crate) struct Montgomery<T: DoubleInt> {
+    a: T,
+    n: T,
+}
+
+impl<T: DoubleInt> Montgomery<T> {
+    /// computes x/R mod n efficiently
+    fn reduce(&self, x: T::DoubleWidth) -> T {
+        let t_bits = T::zero().count_zeros() as usize;
+
+        debug_assert!(x < (self.n.as_double_width()) << t_bits);
+        // TODO: optimize
+        let Montgomery { a, n } = self;
+        let m = T::from_double_width(x).wrapping_mul(a);
+        let nm = (n.as_double_width()) * (m.as_double_width());
+        let (xnm, overflow) = x.overflowing_add(&nm); // x + n*m
+        debug_assert_eq!(
+            xnm % (T::DoubleWidth::one() << T::zero().count_zeros() as usize),
+            T::DoubleWidth::zero()
+        );
+
+        // (x + n*m) / R
+        // in case of overflow, this is (2¹²⁸ + xnm)/2⁶⁴ - n = xnm/2⁶⁴ + (2⁶⁴ - n)
+        let y = T::from_double_width(xnm >> t_bits)
+            + if !overflow {
+                T::zero()
+            } else {
+                n.wrapping_neg()
+            };
+
+        if y >= *n {
+            y - *n
+        } else {
+            y
+        }
+    }
+}
+
+impl<T: DoubleInt> Arithmetic for Montgomery<T> {
+    // Montgomery transform, R=2⁶⁴
+    // Provides fast arithmetic mod n (n odd, u64)
+    type ModInt = T;
+
+    fn new(n: u64) -> Self {
+        debug_assert!(T::zero().count_zeros() >= 64 || n < (1 << T::zero().count_zeros() as usize));
+        let n = T::from_u64(n);
+        let a = modular_inverse(n).wrapping_neg();
+        debug_assert_eq!(n.wrapping_mul(&a), T::one().wrapping_neg());
+        Montgomery { a, n }
+    }
+
+    fn modulus(&self) -> u64 {
+        self.n.as_u64()
+    }
+
+    fn from_u64(&self, x: u64) -> Self::ModInt {
+        // TODO: optimise!
+        debug_assert!(x < self.n.as_u64());
+        let r = T::from_double_width(
+            ((T::DoubleWidth::from_u64(x)) << T::zero().count_zeros() as usize)
+                % self.n.as_double_width(),
+        );
+        debug_assert_eq!(x, self.to_u64(r));
+        r
+    }
+
+    fn to_u64(&self, n: Self::ModInt) -> u64 {
+        self.reduce(n.as_double_width()).as_u64()
+    }
+
+    fn add(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt {
+        let (r, overflow) = a.overflowing_add(&b);
+
+        // In case of overflow, a+b = 2⁶⁴ + r = (2⁶⁴ - n) + r (working mod n)
+        let r = if !overflow {
+            r
+        } else {
+            r + self.n.wrapping_neg()
+        };
+
+        // Normalize to [0; n[
+        let r = if r < self.n { r } else { r - self.n };
+
+        // Check that r (reduced back to the usual representation) equals
+        // a+b % n
+        #[cfg(debug_assertions)]
+        {
+            let a_r = self.to_u64(a) as u128;
+            let b_r = self.to_u64(b) as u128;
+            let r_r = self.to_u64(r);
+            let r_2 = ((a_r + b_r) % self.n.as_u128()) as u64;
+            debug_assert_eq!(
+                r_r, r_2,
+                "[{}] = {} ≠ {} = {} + {} = [{}] + [{}] mod {}; a = {}",
+                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
+            );
+        }
+        r
+    }
+
+    fn mul(&self, a: Self::ModInt, b: Self::ModInt) -> Self::ModInt {
+        let r = self.reduce(a.as_double_width() * b.as_double_width());
+
+        // Check that r (reduced back to the usual representation) equals
+        // a*b % n
+        #[cfg(debug_assertions)]
+        {
+            let a_r = self.to_u64(a) as u128;
+            let b_r = self.to_u64(b) as u128;
+            let r_r = self.to_u64(r);
+            let r_2: u64 = ((a_r * b_r) % self.n.as_u128()) as u64;
+            debug_assert_eq!(
+                r_r, r_2,
+                "[{}] = {} ≠ {} = {} * {} = [{}] * [{}] mod {}; a = {}",
+                r, r_r, r_2, a_r, b_r, a, b, self.n, self.a
+            );
+        }
+        r
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::parametrized_check;
+
+    fn test_add<A: DoubleInt>() {
+        for n in 0..100 {
+            let n = 2 * n + 1;
+            let m = Montgomery::<A>::new(n);
+            for x in 0..n {
+                let m_x = m.from_u64(x);
+                for y in 0..=x {
+                    let m_y = m.from_u64(y);
+                    println!("{n:?}, {x:?}, {y:?}", n = n, x = x, y = y);
+                    assert_eq!((x + y) % n, m.to_u64(m.add(m_x, m_y)));
+                }
+            }
+        }
+    }
+    parametrized_check!(test_add);
+
+    fn test_multiplication<A: DoubleInt>() {
+        for n in 0..100 {
+            let n = 2 * n + 1;
+            let m = Montgomery::<A>::new(n);
+            for x in 0..n {
+                let m_x = m.from_u64(x);
+                for y in 0..=x {
+                    let m_y = m.from_u64(y);
+                    assert_eq!((x * y) % n, m.to_u64(m.mul(m_x, m_y)));
+                }
+            }
+        }
+    }
+    parametrized_check!(test_multiplication);
+
+    fn test_roundtrip<A: DoubleInt>() {
+        for n in 0..100 {
+            let n = 2 * n + 1;
+            let m = Montgomery::<A>::new(n);
+            for x in 0..n {
+                let x_ = m.from_u64(x);
+                assert_eq!(x, m.to_u64(x_));
+            }
+        }
+    }
+    parametrized_check!(test_roundtrip);
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/numeric/traits.rs.html b/src/uu_factor/numeric/traits.rs.html new file mode 100644 index 000000000..b3927a31c --- /dev/null +++ b/src/uu_factor/numeric/traits.rs.html @@ -0,0 +1,185 @@ +traits.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2020 Alex Lyon  <arcterus@mail.com>
+// * (c) 2020 nicoo      <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+pub(crate) use num_traits::{
+    identities::{One, Zero},
+    ops::overflowing::OverflowingAdd,
+};
+use num_traits::{
+    int::PrimInt,
+    ops::wrapping::{WrappingMul, WrappingNeg, WrappingSub},
+};
+use std::fmt::{Debug, Display};
+
+pub(crate) trait Int:
+    Display + Debug + PrimInt + OverflowingAdd + WrappingNeg + WrappingSub + WrappingMul
+{
+    fn as_u64(&self) -> u64;
+    fn from_u64(n: u64) -> Self;
+
+    #[cfg(debug_assertions)]
+    fn as_u128(&self) -> u128;
+}
+
+pub(crate) trait DoubleInt: Int {
+    /// An integer type with twice the width of `Self`.
+    /// In particular, multiplications (of `Int` values) can be performed in
+    ///  `Self::DoubleWidth` without possibility of overflow.
+    type DoubleWidth: Int;
+
+    fn as_double_width(self) -> Self::DoubleWidth;
+    fn from_double_width(n: Self::DoubleWidth) -> Self;
+}
+
+macro_rules! int {
+    ( $x:ty ) => {
+        impl Int for $x {
+            fn as_u64(&self) -> u64 {
+                *self as u64
+            }
+            fn from_u64(n: u64) -> Self {
+                n as _
+            }
+            #[cfg(debug_assertions)]
+            fn as_u128(&self) -> u128 {
+                *self as u128
+            }
+        }
+    };
+}
+macro_rules! double_int {
+    ( $x:ty, $y:ty ) => {
+        int!($x);
+        impl DoubleInt for $x {
+            type DoubleWidth = $y;
+
+            fn as_double_width(self) -> $y {
+                self as _
+            }
+            fn from_double_width(n: $y) -> $x {
+                n as _
+            }
+        }
+    };
+}
+double_int!(u32, u64);
+double_int!(u64, u128);
+int!(u128);
+
+/// Helper macro for instantiating tests over u32 and u64
+#[cfg(test)]
+#[macro_export]
+macro_rules! parametrized_check {
+    ( $f:ident ) => {
+        paste::item! {
+            #[test]
+            fn [< $f _ u32 >]() {
+                $f::<u32>()
+            }
+            #[test]
+            fn [< $f _ u64 >]() {
+                $f::<u64>()
+            }
+        }
+    };
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/rho.rs.html b/src/uu_factor/rho.rs.html new file mode 100644 index 000000000..f2807cea9 --- /dev/null +++ b/src/uu_factor/rho.rs.html @@ -0,0 +1,99 @@ +rho.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2015 Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
+// * (c) 2020 nicoo <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+use rand::distributions::{Distribution, Uniform};
+use rand::rngs::SmallRng;
+use rand::{thread_rng, SeedableRng};
+use std::cmp::{max, min};
+
+use crate::numeric::*;
+
+pub(crate) fn find_divisor<A: Arithmetic>(n: A) -> u64 {
+    #![allow(clippy::many_single_char_names)]
+    let mut rand = {
+        let range = Uniform::new(1, n.modulus());
+        let mut rng = SmallRng::from_rng(&mut thread_rng()).unwrap();
+        move || n.from_u64(range.sample(&mut rng))
+    };
+
+    let quadratic = |a, b| move |x| n.add(n.mul(a, n.mul(x, x)), b);
+
+    loop {
+        let f = quadratic(rand(), rand());
+        let mut x = rand();
+        let mut y = x;
+
+        loop {
+            x = f(x);
+            y = f(f(y));
+            let d = {
+                let _x = n.to_u64(x);
+                let _y = n.to_u64(y);
+                gcd(n.modulus(), max(_x, _y) - min(_x, _y))
+            };
+            if d == n.modulus() {
+                // Failure, retry with a different quadratic
+                break;
+            } else if d > 1 {
+                return d;
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_factor/table.rs.html b/src/uu_factor/table.rs.html new file mode 100644 index 000000000..2df29c2fc --- /dev/null +++ b/src/uu_factor/table.rs.html @@ -0,0 +1,207 @@ +table.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) 2015 kwantam <kwantam@gmail.com>
+// * (c) 2020 nicoo   <nicoo@debian.org>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+// spell-checker: ignore (ToDO) INVS
+
+use crate::Factors;
+
+include!(concat!(env!("OUT_DIR"), "/prime_table.rs"));
+
+pub fn factor(num: &mut u64, factors: &mut Factors) {
+    for &(prime, inv, ceil) in PRIME_INVERSIONS_U64 {
+        if *num == 1 {
+            break;
+        }
+
+        // inv = prime^-1 mod 2^64
+        // ceil = floor((2^64-1) / prime)
+        // if (num * inv) mod 2^64 <= ceil, then prime divides num
+        // See https://math.stackexchange.com/questions/1251327/
+        // for a nice explanation.
+        let mut k = 0;
+        loop {
+            let x = num.wrapping_mul(inv);
+
+            // While prime divides num
+            if x <= ceil {
+                *num = x;
+                k += 1;
+                #[cfg(feature = "coz")]
+                coz::progress!("factor found");
+            } else {
+                if k > 0 {
+                    factors.add(prime, k);
+                }
+                break;
+            }
+        }
+    }
+}
+
+pub const CHUNK_SIZE: usize = 8;
+pub fn factor_chunk(n_s: &mut [u64; CHUNK_SIZE], f_s: &mut [Factors; CHUNK_SIZE]) {
+    for &(prime, inv, ceil) in PRIME_INVERSIONS_U64 {
+        if n_s[0] == 1 && n_s[1] == 1 && n_s[2] == 1 && n_s[3] == 1 {
+            break;
+        }
+
+        for (num, factors) in n_s.iter_mut().zip(f_s.iter_mut()) {
+            if *num == 1 {
+                continue;
+            }
+            let mut k = 0;
+            loop {
+                let x = num.wrapping_mul(inv);
+
+                // While prime divides num
+                if x <= ceil {
+                    *num = x;
+                    k += 1;
+                } else {
+                    if k > 0 {
+                        factors.add(prime, k);
+                    }
+                    break;
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::Factors;
+    use quickcheck::quickcheck;
+    use rand::{rngs::SmallRng, Rng, SeedableRng};
+
+    quickcheck! {
+        fn chunk_vs_iter(seed: u64) -> () {
+            let mut rng = SmallRng::seed_from_u64(seed);
+            let mut n_c: [u64; CHUNK_SIZE] = rng.gen();
+            let mut f_c: [Factors; CHUNK_SIZE] = rng.gen();
+
+            let mut n_i = n_c;
+            let mut f_i = f_c.clone();
+            for (n, f) in n_i.iter_mut().zip(f_i.iter_mut()) {
+                factor(n, f);
+            }
+
+            factor_chunk(&mut n_c, &mut f_c);
+
+            assert_eq!(n_i, n_c);
+            assert_eq!(f_i, f_c);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_false/false.rs.html b/src/uu_false/false.rs.html new file mode 100644 index 000000000..340927dfd --- /dev/null +++ b/src/uu_false/false.rs.html @@ -0,0 +1,49 @@ +false.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::App;
+use uucore::error::UResult;
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    uu_app().get_matches_from(args);
+    Err(1.into())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+}
+
+
\ No newline at end of file diff --git a/src/uu_fmt/fmt.rs.html b/src/uu_fmt/fmt.rs.html new file mode 100644 index 000000000..31087ba4a --- /dev/null +++ b/src/uu_fmt/fmt.rs.html @@ -0,0 +1,675 @@ +fmt.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+
+//  * This file is part of `fmt` from the uutils coreutils package.
+//  *
+//  * (c) kwantam <kwantam@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) PSKIP linebreak ostream parasplit tabwidth xanti xprefix
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::cmp;
+use std::fs::File;
+use std::io::{stdin, stdout, Write};
+use std::io::{BufReader, BufWriter, Read};
+
+use self::linebreak::break_lines;
+use self::parasplit::ParagraphStream;
+
+macro_rules! silent_unwrap(
+    ($exp:expr) => (
+        match $exp {
+            Ok(_) => (),
+            Err(_) => ::std::process::exit(1),
+        }
+    )
+);
+
+mod linebreak;
+mod parasplit;
+
+static ABOUT: &str = "Reformat paragraphs from input files (or stdin) to stdout.";
+static MAX_WIDTH: usize = 2500;
+
+static OPT_CROWN_MARGIN: &str = "crown-margin";
+static OPT_TAGGED_PARAGRAPH: &str = "tagged-paragraph";
+static OPT_PRESERVE_HEADERS: &str = "preserve-headers";
+static OPT_SPLIT_ONLY: &str = "split-only";
+static OPT_UNIFORM_SPACING: &str = "uniform-spacing";
+static OPT_PREFIX: &str = "prefix";
+static OPT_SKIP_PREFIX: &str = "skip-prefix";
+static OPT_EXACT_PREFIX: &str = "exact-prefix";
+static OPT_EXACT_SKIP_PREFIX: &str = "exact-skip-prefix";
+static OPT_WIDTH: &str = "width";
+static OPT_GOAL: &str = "goal";
+static OPT_QUICK: &str = "quick";
+static OPT_TAB_WIDTH: &str = "tab-width";
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!("{} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+pub type FileOrStdReader = BufReader<Box<dyn Read + 'static>>;
+pub struct FmtOptions {
+    crown: bool,
+    tagged: bool,
+    mail: bool,
+    split_only: bool,
+    use_prefix: bool,
+    prefix: String,
+    xprefix: bool,
+    use_anti_prefix: bool,
+    anti_prefix: String,
+    xanti_prefix: bool,
+    uniform: bool,
+    quick: bool,
+    width: usize,
+    goal: usize,
+    tabwidth: usize,
+}
+
+#[allow(clippy::cognitive_complexity)]
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mut files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let mut fmt_opts = FmtOptions {
+        crown: false,
+        tagged: false,
+        mail: false,
+        uniform: false,
+        quick: false,
+        split_only: false,
+        use_prefix: false,
+        prefix: String::new(),
+        xprefix: false,
+        use_anti_prefix: false,
+        anti_prefix: String::new(),
+        xanti_prefix: false,
+        width: 79,
+        goal: 74,
+        tabwidth: 8,
+    };
+
+    fmt_opts.tagged = matches.is_present(OPT_TAGGED_PARAGRAPH);
+    if matches.is_present(OPT_CROWN_MARGIN) {
+        fmt_opts.crown = true;
+        fmt_opts.tagged = false;
+    }
+    fmt_opts.mail = matches.is_present(OPT_PRESERVE_HEADERS);
+    fmt_opts.uniform = matches.is_present(OPT_UNIFORM_SPACING);
+    fmt_opts.quick = matches.is_present(OPT_QUICK);
+    if matches.is_present(OPT_SPLIT_ONLY) {
+        fmt_opts.split_only = true;
+        fmt_opts.crown = false;
+        fmt_opts.tagged = false;
+    }
+    fmt_opts.xprefix = matches.is_present(OPT_EXACT_PREFIX);
+    fmt_opts.xanti_prefix = matches.is_present(OPT_SKIP_PREFIX);
+
+    if let Some(s) = matches.value_of(OPT_PREFIX).map(String::from) {
+        fmt_opts.prefix = s;
+        fmt_opts.use_prefix = true;
+    };
+
+    if let Some(s) = matches.value_of(OPT_SKIP_PREFIX).map(String::from) {
+        fmt_opts.anti_prefix = s;
+        fmt_opts.use_anti_prefix = true;
+    };
+
+    if let Some(s) = matches.value_of(OPT_WIDTH) {
+        fmt_opts.width = match s.parse::<usize>() {
+            Ok(t) => t,
+            Err(e) => {
+                crash!(1, "Invalid WIDTH specification: `{}': {}", s, e);
+            }
+        };
+        if fmt_opts.width > MAX_WIDTH {
+            crash!(
+                1,
+                "invalid width: '{}': Numerical result out of range",
+                fmt_opts.width
+            );
+        }
+        fmt_opts.goal = cmp::min(fmt_opts.width * 94 / 100, fmt_opts.width - 3);
+    };
+
+    if let Some(s) = matches.value_of(OPT_GOAL) {
+        fmt_opts.goal = match s.parse::<usize>() {
+            Ok(t) => t,
+            Err(e) => {
+                crash!(1, "Invalid GOAL specification: `{}': {}", s, e);
+            }
+        };
+        if !matches.is_present(OPT_WIDTH) {
+            fmt_opts.width = cmp::max(fmt_opts.goal * 100 / 94, fmt_opts.goal + 3);
+        } else if fmt_opts.goal > fmt_opts.width {
+            crash!(1, "GOAL cannot be greater than WIDTH.");
+        }
+    };
+
+    if let Some(s) = matches.value_of(OPT_TAB_WIDTH) {
+        fmt_opts.tabwidth = match s.parse::<usize>() {
+            Ok(t) => t,
+            Err(e) => {
+                crash!(1, "Invalid TABWIDTH specification: `{}': {}", s, e);
+            }
+        };
+    };
+
+    if fmt_opts.tabwidth < 1 {
+        fmt_opts.tabwidth = 1;
+    }
+
+    // immutable now
+    let fmt_opts = fmt_opts;
+
+    if files.is_empty() {
+        files.push("-".to_owned());
+    }
+
+    let mut ostream = BufWriter::new(stdout());
+
+    for i in files.iter().map(|x| &x[..]) {
+        let mut fp = match i {
+            "-" => BufReader::new(Box::new(stdin()) as Box<dyn Read + 'static>),
+            _ => match File::open(i) {
+                Ok(f) => BufReader::new(Box::new(f) as Box<dyn Read + 'static>),
+                Err(e) => {
+                    show_warning!("{}: {}", i, e);
+                    continue;
+                }
+            },
+        };
+        let p_stream = ParagraphStream::new(&fmt_opts, &mut fp);
+        for para_result in p_stream {
+            match para_result {
+                Err(s) => {
+                    silent_unwrap!(ostream.write_all(s.as_bytes()));
+                    silent_unwrap!(ostream.write_all(b"\n"));
+                }
+                Ok(para) => break_lines(&para, &fmt_opts, &mut ostream),
+            }
+        }
+
+        // flush the output after each file
+        silent_unwrap!(ostream.flush());
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_CROWN_MARGIN)
+                .short("c")
+                .long(OPT_CROWN_MARGIN)
+                .help(
+                    "First and second line of paragraph \
+                    may have different indentations, in which \
+                    case the first line's indentation is preserved, \
+                    and each subsequent line's indentation matches the second line.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_TAGGED_PARAGRAPH)
+                .short("t")
+                .long("tagged-paragraph")
+                .help(
+                    "Like -c, except that the first and second line of a paragraph *must* \
+                    have different indentation or they are treated as separate paragraphs.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_PRESERVE_HEADERS)
+                .short("m")
+                .long("preserve-headers")
+                .help(
+                    "Attempt to detect and preserve mail headers in the input. \
+                    Be careful when combining this flag with -p.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_SPLIT_ONLY)
+                .short("s")
+                .long("split-only")
+                .help("Split lines only, do not reflow."),
+        )
+        .arg(
+            Arg::with_name(OPT_UNIFORM_SPACING)
+                .short("u")
+                .long("uniform-spacing")
+                .help(
+                    "Insert exactly one \
+                    space between words, and two between sentences. \
+                    Sentence breaks in the input are detected as [?!.] \
+                    followed by two spaces or a newline; other punctuation \
+                    is not interpreted as a sentence break.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_PREFIX)
+                .short("p")
+                .long("prefix")
+                .help(
+                    "Reformat only lines \
+                    beginning with PREFIX, reattaching PREFIX to reformatted lines. \
+                    Unless -x is specified, leading whitespace will be ignored \
+                    when matching PREFIX.",
+                )
+                .value_name("PREFIX"),
+        )
+        .arg(
+            Arg::with_name(OPT_SKIP_PREFIX)
+                .short("P")
+                .long("skip-prefix")
+                .help(
+                    "Do not reformat lines \
+                    beginning with PSKIP. Unless -X is specified, leading whitespace \
+                    will be ignored when matching PSKIP",
+                )
+                .value_name("PSKIP"),
+        )
+        .arg(
+            Arg::with_name(OPT_EXACT_PREFIX)
+                .short("x")
+                .long("exact-prefix")
+                .help(
+                    "PREFIX must match at the \
+                    beginning of the line with no preceding whitespace.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_EXACT_SKIP_PREFIX)
+                .short("X")
+                .long("exact-skip-prefix")
+                .help(
+                    "PSKIP must match at the \
+                    beginning of the line with no preceding whitespace.",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_WIDTH)
+                .short("w")
+                .long("width")
+                .help("Fill output lines up to a maximum of WIDTH columns, default 79.")
+                .value_name("WIDTH"),
+        )
+        .arg(
+            Arg::with_name(OPT_GOAL)
+                .short("g")
+                .long("goal")
+                .help("Goal width, default ~0.94*WIDTH. Must be less than WIDTH.")
+                .value_name("GOAL"),
+        )
+        .arg(Arg::with_name(OPT_QUICK).short("q").long("quick").help(
+            "Break lines more quickly at the \
+            expense of a potentially more ragged appearance.",
+        ))
+        .arg(
+            Arg::with_name(OPT_TAB_WIDTH)
+                .short("T")
+                .long("tab-width")
+                .help(
+                    "Treat tabs as TABWIDTH spaces for \
+                    determining line length, default 8. Note that this is used only for \
+                    calculating line lengths; tabs are preserved in the output.",
+                )
+                .value_name("TABWIDTH"),
+        )
+        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_fmt/linebreak.rs.html b/src/uu_fmt/linebreak.rs.html new file mode 100644 index 000000000..4d2c06831 --- /dev/null +++ b/src/uu_fmt/linebreak.rs.html @@ -0,0 +1,1025 @@ +linebreak.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+
+//  * This file is part of `fmt` from the uutils coreutils package.
+//  *
+//  * (c) kwantam <kwantam@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) INFTY MULT accum breakwords linebreak linebreaking linebreaks linelen maxlength minlength nchars ostream overlen parasplit plass posn powf punct signum slen sstart tabwidth tlen underlen winfo wlen wordlen
+
+use std::cmp;
+use std::i64;
+use std::io::{BufWriter, Stdout, Write};
+use std::mem;
+
+use crate::parasplit::{ParaWords, Paragraph, WordInfo};
+use crate::FmtOptions;
+
+struct BreakArgs<'a> {
+    opts: &'a FmtOptions,
+    init_len: usize,
+    indent_str: &'a str,
+    indent_len: usize,
+    uniform: bool,
+    ostream: &'a mut BufWriter<Stdout>,
+}
+
+impl<'a> BreakArgs<'a> {
+    fn compute_width<'b>(&self, winfo: &WordInfo<'b>, posn: usize, fresh: bool) -> usize {
+        if fresh {
+            0
+        } else {
+            let post = winfo.after_tab;
+            match winfo.before_tab {
+                None => post,
+                Some(pre) => {
+                    post + ((pre + posn) / self.opts.tabwidth + 1) * self.opts.tabwidth - posn
+                }
+            }
+        }
+    }
+}
+
+pub fn break_lines(para: &Paragraph, opts: &FmtOptions, ostream: &mut BufWriter<Stdout>) {
+    // indent
+    let p_indent = &para.indent_str[..];
+    let p_indent_len = para.indent_len;
+
+    // words
+    let p_words = ParaWords::new(opts, para);
+    let mut p_words_words = p_words.words();
+
+    // the first word will *always* appear on the first line
+    // make sure of this here
+    let (w, w_len) = match p_words_words.next() {
+        Some(winfo) => (winfo.word, winfo.word_nchars),
+        None => {
+            silent_unwrap!(ostream.write_all(b"\n"));
+            return;
+        }
+    };
+    // print the init, if it exists, and get its length
+    let p_init_len = w_len
+        + if opts.crown || opts.tagged {
+            // handle "init" portion
+            silent_unwrap!(ostream.write_all(para.init_str.as_bytes()));
+            para.init_len
+        } else if !para.mail_header {
+            // for non-(crown, tagged) that's the same as a normal indent
+            silent_unwrap!(ostream.write_all(p_indent.as_bytes()));
+            p_indent_len
+        } else {
+            // except that mail headers get no indent at all
+            0
+        };
+    // write first word after writing init
+    silent_unwrap!(ostream.write_all(w.as_bytes()));
+
+    // does this paragraph require uniform spacing?
+    let uniform = para.mail_header || opts.uniform;
+
+    let mut break_args = BreakArgs {
+        opts,
+        init_len: p_init_len,
+        indent_str: p_indent,
+        indent_len: p_indent_len,
+        uniform,
+        ostream,
+    };
+
+    if opts.quick || para.mail_header {
+        break_simple(p_words_words, &mut break_args);
+    } else {
+        break_knuth_plass(p_words_words, &mut break_args);
+    }
+}
+
+// break_simple implements a "greedy" breaking algorithm: print words until
+// maxlength would be exceeded, then print a linebreak and indent and continue.
+fn break_simple<'a, T: Iterator<Item = &'a WordInfo<'a>>>(iter: T, args: &mut BreakArgs<'a>) {
+    iter.fold((args.init_len, false), |l, winfo| {
+        accum_words_simple(args, l, winfo)
+    });
+    silent_unwrap!(args.ostream.write_all(b"\n"));
+}
+
+fn accum_words_simple<'a>(
+    args: &mut BreakArgs<'a>,
+    (l, prev_punct): (usize, bool),
+    winfo: &'a WordInfo<'a>,
+) -> (usize, bool) {
+    // compute the length of this word, considering how tabs will expand at this position on the line
+    let wlen = winfo.word_nchars + args.compute_width(winfo, l, false);
+
+    let slen = compute_slen(
+        args.uniform,
+        winfo.new_line,
+        winfo.sentence_start,
+        prev_punct,
+    );
+
+    if l + wlen + slen > args.opts.width {
+        write_newline(args.indent_str, args.ostream);
+        write_with_spaces(&winfo.word[winfo.word_start..], 0, args.ostream);
+        (args.indent_len + winfo.word_nchars, winfo.ends_punct)
+    } else {
+        write_with_spaces(winfo.word, slen, args.ostream);
+        (l + wlen + slen, winfo.ends_punct)
+    }
+}
+
+// break_knuth_plass implements an "optimal" breaking algorithm in the style of
+//    Knuth, D.E., and Plass, M.F. "Breaking Paragraphs into Lines." in Software,
+//    Practice and Experience. Vol. 11, No. 11, November 1981.
+//    http://onlinelibrary.wiley.com/doi/10.1002/spe.4380111102/pdf
+fn break_knuth_plass<'a, T: Clone + Iterator<Item = &'a WordInfo<'a>>>(
+    mut iter: T,
+    args: &mut BreakArgs<'a>,
+) {
+    // run the algorithm to get the breakpoints
+    let breakpoints = find_kp_breakpoints(iter.clone(), args);
+
+    // iterate through the breakpoints (note that breakpoints is in reverse break order, so we .rev() it
+    let (mut prev_punct, mut fresh) = breakpoints.iter().rev().fold(
+        (false, false),
+        |(mut prev_punct, mut fresh), &(next_break, break_before)| {
+            if fresh {
+                write_newline(args.indent_str, args.ostream);
+            }
+            // at each breakpoint, keep emitting words until we find the word matching this breakpoint
+            for winfo in &mut iter {
+                let (slen, word) = slice_if_fresh(
+                    fresh,
+                    winfo.word,
+                    winfo.word_start,
+                    args.uniform,
+                    winfo.new_line,
+                    winfo.sentence_start,
+                    prev_punct,
+                );
+                fresh = false;
+                prev_punct = winfo.ends_punct;
+
+                // We find identical breakpoints here by comparing addresses of the references.
+                // This is OK because the backing vector is not mutating once we are linebreaking.
+                let winfo_ptr = winfo as *const _;
+                let next_break_ptr = next_break as *const _;
+                if winfo_ptr == next_break_ptr {
+                    // OK, we found the matching word
+                    if break_before {
+                        write_newline(args.indent_str, args.ostream);
+                        write_with_spaces(&winfo.word[winfo.word_start..], 0, args.ostream);
+                    } else {
+                        // breaking after this word, so that means "fresh" is true for the next iteration
+                        write_with_spaces(word, slen, args.ostream);
+                        fresh = true;
+                    }
+                    break;
+                } else {
+                    write_with_spaces(word, slen, args.ostream);
+                }
+            }
+            (prev_punct, fresh)
+        },
+    );
+
+    // after the last linebreak, write out the rest of the final line.
+    for winfo in iter {
+        if fresh {
+            write_newline(args.indent_str, args.ostream);
+        }
+        let (slen, word) = slice_if_fresh(
+            fresh,
+            winfo.word,
+            winfo.word_start,
+            args.uniform,
+            winfo.new_line,
+            winfo.sentence_start,
+            prev_punct,
+        );
+        prev_punct = winfo.ends_punct;
+        fresh = false;
+        write_with_spaces(word, slen, args.ostream);
+    }
+    silent_unwrap!(args.ostream.write_all(b"\n"));
+}
+
+struct LineBreak<'a> {
+    prev: usize,
+    linebreak: Option<&'a WordInfo<'a>>,
+    break_before: bool,
+    demerits: i64,
+    prev_rat: f32,
+    length: usize,
+    fresh: bool,
+}
+
+fn find_kp_breakpoints<'a, T: Iterator<Item = &'a WordInfo<'a>>>(
+    iter: T,
+    args: &BreakArgs<'a>,
+) -> Vec<(&'a WordInfo<'a>, bool)> {
+    let mut iter = iter.peekable();
+    // set up the initial null linebreak
+    let mut linebreaks = vec![LineBreak {
+        prev: 0,
+        linebreak: None,
+        break_before: false,
+        demerits: 0,
+        prev_rat: 0.0f32,
+        length: args.init_len,
+        fresh: false,
+    }];
+    // this vec holds the current active linebreaks; next_ holds the breaks that will be active for
+    // the next word
+    let active_breaks = &mut vec![0];
+    let next_active_breaks = &mut vec![];
+
+    let stretch = (args.opts.width - args.opts.goal) as isize;
+    let minlength = args.opts.goal - stretch as usize;
+    let mut new_linebreaks = vec![];
+    let mut is_sentence_start = false;
+    let mut least_demerits = 0;
+    loop {
+        let w = match iter.next() {
+            None => break,
+            Some(w) => w,
+        };
+
+        // if this is the last word, we don't add additional demerits for this break
+        let (is_last_word, is_sentence_end) = match iter.peek() {
+            None => (true, true),
+            Some(&&WordInfo {
+                sentence_start: st,
+                new_line: nl,
+                ..
+            }) => (false, st || (nl && w.ends_punct)),
+        };
+
+        // should we be adding extra space at the beginning of the next sentence?
+        let slen = compute_slen(args.uniform, w.new_line, is_sentence_start, false);
+
+        let mut ld_new = i64::MAX;
+        let mut ld_next = i64::MAX;
+        let mut ld_idx = 0;
+        new_linebreaks.clear();
+        next_active_breaks.clear();
+        // go through each active break, extending it and possibly adding a new active
+        // break if we are above the minimum required length
+        for &i in active_breaks.iter() {
+            let active = &mut linebreaks[i];
+            // normalize demerits to avoid overflow, and record if this is the least
+            active.demerits -= least_demerits;
+            if active.demerits < ld_next {
+                ld_next = active.demerits;
+                ld_idx = i;
+            }
+
+            // get the new length
+            let tlen = w.word_nchars
+                + args.compute_width(w, active.length, active.fresh)
+                + slen
+                + active.length;
+
+            // if tlen is longer than args.opts.width, we drop this break from the active list
+            // otherwise, we extend the break, and possibly add a new break at this point
+            if tlen <= args.opts.width {
+                // this break will still be active next time
+                next_active_breaks.push(i);
+                // we can put this word on this line
+                active.fresh = false;
+                active.length = tlen;
+
+                // if we're above the minlength, we can also consider breaking here
+                if tlen >= minlength {
+                    let (new_demerits, new_ratio) = if is_last_word {
+                        // there is no penalty for the final line's length
+                        (0, 0.0)
+                    } else {
+                        compute_demerits(
+                            args.opts.goal as isize - tlen as isize,
+                            stretch,
+                            w.word_nchars as isize,
+                            active.prev_rat,
+                        )
+                    };
+
+                    // do not even consider adding a line that has too many demerits
+                    // also, try to detect overflow by checking signum
+                    let total_demerits = new_demerits + active.demerits;
+                    if new_demerits < BAD_INFTY_SQ
+                        && total_demerits < ld_new
+                        && active.demerits.signum() <= new_demerits.signum()
+                    {
+                        ld_new = total_demerits;
+                        new_linebreaks.push(LineBreak {
+                            prev: i,
+                            linebreak: Some(w),
+                            break_before: false,
+                            demerits: total_demerits,
+                            prev_rat: new_ratio,
+                            length: args.indent_len,
+                            fresh: true,
+                        });
+                    }
+                }
+            }
+        }
+
+        // if we generated any new linebreaks, add the last one to the list
+        // the last one is always the best because we don't add to new_linebreaks unless
+        // it's better than the best one so far
+        match new_linebreaks.pop() {
+            None => (),
+            Some(lb) => {
+                next_active_breaks.push(linebreaks.len());
+                linebreaks.push(lb);
+            }
+        }
+
+        if next_active_breaks.is_empty() {
+            // every potential linebreak is too long! choose the linebreak with the least demerits, ld_idx
+            let new_break =
+                restart_active_breaks(args, &linebreaks[ld_idx], ld_idx, w, slen, minlength);
+            next_active_breaks.push(linebreaks.len());
+            linebreaks.push(new_break);
+            least_demerits = 0;
+        } else {
+            // next time around, normalize out the demerits fields
+            // on active linebreaks to make overflow less likely
+            least_demerits = cmp::max(ld_next, 0);
+        }
+        // swap in new list of active breaks
+        mem::swap(active_breaks, next_active_breaks);
+        // If this was the last word in a sentence, the next one must be the first in the next.
+        is_sentence_start = is_sentence_end;
+    }
+
+    // return the best path
+    build_best_path(&linebreaks, active_breaks)
+}
+
+fn build_best_path<'a>(paths: &[LineBreak<'a>], active: &[usize]) -> Vec<(&'a WordInfo<'a>, bool)> {
+    let mut breakwords = vec![];
+    // of the active paths, we select the one with the fewest demerits
+    let mut best_idx = match active.iter().min_by_key(|&&a| paths[a].demerits) {
+        None => crash!(
+            1,
+            "Failed to find a k-p linebreak solution. This should never happen."
+        ),
+        Some(&s) => s,
+    };
+
+    // now, chase the pointers back through the break list, recording
+    // the words at which we should break
+    loop {
+        let next_best = &paths[best_idx];
+        match next_best.linebreak {
+            None => return breakwords,
+            Some(prev) => {
+                breakwords.push((prev, next_best.break_before));
+                best_idx = next_best.prev
+            }
+        }
+    }
+}
+
+// "infinite" badness is more like (1+BAD_INFTY)^2 because of how demerits are computed
+const BAD_INFTY: i64 = 10_000_000;
+const BAD_INFTY_SQ: i64 = BAD_INFTY * BAD_INFTY;
+// badness = BAD_MULT * abs(r) ^ 3
+const BAD_MULT: f32 = 100.0;
+// DR_MULT is multiplier for delta-R between lines
+const DR_MULT: f32 = 600.0;
+// DL_MULT is penalty multiplier for short words at end of line
+const DL_MULT: f32 = 300.0;
+
+fn compute_demerits(delta_len: isize, stretch: isize, wlen: isize, prev_rat: f32) -> (i64, f32) {
+    // how much stretch are we using?
+    let ratio = if delta_len == 0 {
+        0.0f32
+    } else {
+        delta_len as f32 / stretch as f32
+    };
+
+    // compute badness given the stretch ratio
+    let bad_linelen = if ratio.abs() > 1.0f32 {
+        BAD_INFTY
+    } else {
+        (BAD_MULT * ratio.powf(3f32).abs()) as i64
+    };
+
+    // we penalize lines ending in really short words
+    let bad_wordlen = if wlen >= stretch {
+        0
+    } else {
+        (DL_MULT
+            * ((stretch - wlen) as f32 / (stretch - 1) as f32)
+                .powf(3f32)
+                .abs()) as i64
+    };
+
+    // we penalize lines that have very different ratios from previous lines
+    let bad_delta_r = (DR_MULT * (((ratio - prev_rat) / 2.0).powf(3f32)).abs()) as i64;
+
+    let demerits = i64::pow(1 + bad_linelen + bad_wordlen + bad_delta_r, 2);
+
+    (demerits, ratio)
+}
+
+fn restart_active_breaks<'a>(
+    args: &BreakArgs<'a>,
+    active: &LineBreak<'a>,
+    act_idx: usize,
+    w: &'a WordInfo<'a>,
+    slen: usize,
+    min: usize,
+) -> LineBreak<'a> {
+    let (break_before, line_length) = if active.fresh {
+        // never break before a word if that word would be the first on a line
+        (false, args.indent_len)
+    } else {
+        // choose the lesser evil: breaking too early, or breaking too late
+        let wlen = w.word_nchars + args.compute_width(w, active.length, active.fresh);
+        let underlen = (min - active.length) as isize;
+        let overlen = ((wlen + slen + active.length) - args.opts.width) as isize;
+        if overlen > underlen {
+            // break early, put this word on the next line
+            (true, args.indent_len + w.word_nchars)
+        } else {
+            (false, args.indent_len)
+        }
+    };
+
+    // restart the linebreak. This will be our only active path.
+    LineBreak {
+        prev: act_idx,
+        linebreak: Some(w),
+        break_before,
+        demerits: 0, // this is the only active break, so we can reset the demerit count
+        prev_rat: if break_before { 1.0 } else { -1.0 },
+        length: line_length,
+        fresh: !break_before,
+    }
+}
+
+// Number of spaces to add before a word, based on mode, newline, sentence start.
+fn compute_slen(uniform: bool, newline: bool, start: bool, punct: bool) -> usize {
+    if uniform || newline {
+        if start || (newline && punct) {
+            2
+        } else {
+            1
+        }
+    } else {
+        0
+    }
+}
+
+// If we're on a fresh line, slen=0 and we slice off leading whitespace.
+// Otherwise, compute slen and leave whitespace alone.
+fn slice_if_fresh(
+    fresh: bool,
+    word: &str,
+    start: usize,
+    uniform: bool,
+    newline: bool,
+    sstart: bool,
+    punct: bool,
+) -> (usize, &str) {
+    if fresh {
+        (0, &word[start..])
+    } else {
+        (compute_slen(uniform, newline, sstart, punct), word)
+    }
+}
+
+// Write a newline and add the indent.
+fn write_newline(indent: &str, ostream: &mut BufWriter<Stdout>) {
+    silent_unwrap!(ostream.write_all(b"\n"));
+    silent_unwrap!(ostream.write_all(indent.as_bytes()));
+}
+
+// Write the word, along with slen spaces.
+fn write_with_spaces(word: &str, slen: usize, ostream: &mut BufWriter<Stdout>) {
+    if slen == 2 {
+        silent_unwrap!(ostream.write_all(b"  "));
+    } else if slen == 1 {
+        silent_unwrap!(ostream.write_all(b" "));
+    }
+    silent_unwrap!(ostream.write_all(word.as_bytes()));
+}
+
+
\ No newline at end of file diff --git a/src/uu_fmt/parasplit.rs.html b/src/uu_fmt/parasplit.rs.html new file mode 100644 index 000000000..35e36ef75 --- /dev/null +++ b/src/uu_fmt/parasplit.rs.html @@ -0,0 +1,1259 @@ +parasplit.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+
+//  * This file is part of `fmt` from the uutils coreutils package.
+//  *
+//  * (c) kwantam <kwantam@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) INFTY MULT PSKIP accum aftertab beforetab breakwords fmt's formatline linebreak linebreaking linebreaks linelen maxlength minlength nchars noformat noformatline ostream overlen parasplit pfxind plass pmatch poffset posn powf prefixindent punct signum slen sstart tabwidth tlen underlen winfo wlen wordlen wordsplits xanti xprefix
+
+use std::io::{BufRead, Lines};
+use std::iter::Peekable;
+use std::slice::Iter;
+use unicode_width::UnicodeWidthChar;
+
+use crate::FileOrStdReader;
+use crate::FmtOptions;
+
+fn char_width(c: char) -> usize {
+    if (c as usize) < 0xA0 {
+        // if it is ASCII, call it exactly 1 wide (including control chars)
+        // calling control chars' widths 1 is consistent with OpenBSD fmt
+        1
+    } else {
+        // otherwise, get the unicode width
+        // note that we shouldn't actually get None here because only c < 0xA0
+        // can return None, but for safety and future-proofing we do it this way
+        UnicodeWidthChar::width(c).unwrap_or(1)
+    }
+}
+
+// lines with PSKIP, lacking PREFIX, or which are entirely blank are
+// NoFormatLines; otherwise, they are FormatLines
+#[derive(Debug)]
+pub enum Line {
+    FormatLine(FileLine),
+    NoFormatLine(String, bool),
+}
+
+impl Line {
+    // when we know that it's a FormatLine, as in the ParagraphStream iterator
+    fn get_formatline(self) -> FileLine {
+        match self {
+            Line::FormatLine(fl) => fl,
+            Line::NoFormatLine(..) => panic!("Found NoFormatLine when expecting FormatLine"),
+        }
+    }
+
+    // when we know that it's a NoFormatLine, as in the ParagraphStream iterator
+    fn get_noformatline(self) -> (String, bool) {
+        match self {
+            Line::NoFormatLine(s, b) => (s, b),
+            Line::FormatLine(..) => panic!("Found FormatLine when expecting NoFormatLine"),
+        }
+    }
+}
+
+// each line's prefix has to be considered to know whether to merge it with
+// the next line or not
+#[derive(Debug)]
+pub struct FileLine {
+    line: String,
+    indent_end: usize, // the end of the indent, always the start of the text
+    pfxind_end: usize, // the end of the PREFIX's indent, that is, the spaces before the prefix
+    indent_len: usize, // display length of indent taking into account tabs
+    prefix_len: usize, // PREFIX indent length taking into account tabs
+}
+
+// iterator that produces a stream of Lines from a file
+pub struct FileLines<'a> {
+    opts: &'a FmtOptions,
+    lines: Lines<&'a mut FileOrStdReader>,
+}
+
+impl<'a> FileLines<'a> {
+    fn new<'b>(opts: &'b FmtOptions, lines: Lines<&'b mut FileOrStdReader>) -> FileLines<'b> {
+        FileLines { opts, lines }
+    }
+
+    // returns true if this line should be formatted
+    fn match_prefix(&self, line: &str) -> (bool, usize) {
+        if !self.opts.use_prefix {
+            return (true, 0);
+        }
+
+        FileLines::match_prefix_generic(&self.opts.prefix[..], line, self.opts.xprefix)
+    }
+
+    // returns true if this line should be formatted
+    fn match_anti_prefix(&self, line: &str) -> bool {
+        if !self.opts.use_anti_prefix {
+            return true;
+        }
+
+        match FileLines::match_prefix_generic(
+            &self.opts.anti_prefix[..],
+            line,
+            self.opts.xanti_prefix,
+        ) {
+            (true, _) => false,
+            (_, _) => true,
+        }
+    }
+
+    fn match_prefix_generic(pfx: &str, line: &str, exact: bool) -> (bool, usize) {
+        if line.starts_with(pfx) {
+            return (true, 0);
+        }
+
+        if !exact {
+            // we do it this way rather than byte indexing to support unicode whitespace chars
+            for (i, char) in line.char_indices() {
+                if line[i..].starts_with(pfx) {
+                    return (true, i);
+                } else if !char.is_whitespace() {
+                    break;
+                }
+            }
+        }
+
+        (false, 0)
+    }
+
+    fn compute_indent(&self, string: &str, prefix_end: usize) -> (usize, usize, usize) {
+        let mut prefix_len = 0;
+        let mut indent_len = 0;
+        let mut indent_end = 0;
+        for (os, c) in string.char_indices() {
+            if os == prefix_end {
+                // we found the end of the prefix, so this is the printed length of the prefix here
+                prefix_len = indent_len;
+            }
+
+            if (os >= prefix_end) && !c.is_whitespace() {
+                // found first non-whitespace after prefix, this is indent_end
+                indent_end = os;
+                break;
+            } else if c == '\t' {
+                // compute tab length
+                indent_len = (indent_len / self.opts.tabwidth + 1) * self.opts.tabwidth;
+            } else {
+                // non-tab character
+                indent_len += char_width(c);
+            }
+        }
+        (indent_end, prefix_len, indent_len)
+    }
+}
+
+impl<'a> Iterator for FileLines<'a> {
+    type Item = Line;
+
+    fn next(&mut self) -> Option<Line> {
+        let n = match self.lines.next() {
+            Some(t) => match t {
+                Ok(tt) => tt,
+                Err(_) => return None,
+            },
+            None => return None,
+        };
+
+        // if this line is entirely whitespace,
+        // emit a blank line
+        // Err(true) indicates that this was a linebreak,
+        // which is important to know when detecting mail headers
+        if n.chars().all(char::is_whitespace) {
+            return Some(Line::NoFormatLine("".to_owned(), true));
+        }
+
+        let (pmatch, poffset) = self.match_prefix(&n[..]);
+
+        // if this line does not match the prefix,
+        // emit the line unprocessed and iterate again
+        if !pmatch {
+            return Some(Line::NoFormatLine(n, false));
+        }
+
+        // if the line matches the prefix, but is blank after,
+        // don't allow lines to be combined through it (that is,
+        // treat it like a blank line, except that since it's
+        // not truly blank we will not allow mail headers on the
+        // following line)
+        if pmatch
+            && n[poffset + self.opts.prefix.len()..]
+                .chars()
+                .all(char::is_whitespace)
+        {
+            return Some(Line::NoFormatLine(n, false));
+        }
+
+        // skip if this line matches the anti_prefix
+        // (NOTE definition of match_anti_prefix is TRUE if we should process)
+        if !self.match_anti_prefix(&n[..]) {
+            return Some(Line::NoFormatLine(n, false));
+        }
+
+        // figure out the indent, prefix, and prefixindent ending points
+        let prefix_end = poffset + self.opts.prefix.len();
+        let (indent_end, prefix_len, indent_len) = self.compute_indent(&n[..], prefix_end);
+
+        Some(Line::FormatLine(FileLine {
+            line: n,
+            indent_end,
+            pfxind_end: poffset,
+            indent_len,
+            prefix_len,
+        }))
+    }
+}
+
+// a paragraph : a collection of FileLines that are to be formatted
+// plus info about the paragraph's indentation
+// (but we only retain the String from the FileLine; the other info
+// is only there to help us in deciding how to merge lines into Paragraphs
+#[derive(Debug)]
+pub struct Paragraph {
+    lines: Vec<String>,     // the lines of the file
+    pub init_str: String,   // string representing the init, that is, the first line's indent
+    pub init_len: usize,    // printable length of the init string considering TABWIDTH
+    init_end: usize,        // byte location of end of init in first line String
+    pub indent_str: String, // string representing indent
+    pub indent_len: usize,  // length of above
+    indent_end: usize, // byte location of end of indent (in crown and tagged mode, only applies to 2nd line and onward)
+    pub mail_header: bool, // we need to know if this is a mail header because we do word splitting differently in that case
+}
+
+// an iterator producing a stream of paragraphs from a stream of lines
+// given a set of options.
+pub struct ParagraphStream<'a> {
+    lines: Peekable<FileLines<'a>>,
+    next_mail: bool,
+    opts: &'a FmtOptions,
+}
+
+impl<'a> ParagraphStream<'a> {
+    pub fn new<'b>(opts: &'b FmtOptions, reader: &'b mut FileOrStdReader) -> ParagraphStream<'b> {
+        let lines = FileLines::new(opts, reader.lines()).peekable();
+        // at the beginning of the file, we might find mail headers
+        ParagraphStream {
+            lines,
+            next_mail: true,
+            opts,
+        }
+    }
+
+    // detect RFC822 mail header
+    fn is_mail_header(line: &FileLine) -> bool {
+        // a mail header begins with either "From " (envelope sender line)
+        // or with a sequence of printable ASCII chars (33 to 126, inclusive,
+        // except colon) followed by a colon.
+        if line.indent_end > 0 {
+            false
+        } else {
+            let l_slice = &line.line[..];
+            if l_slice.starts_with("From ") {
+                true
+            } else {
+                let colon_posn = match l_slice.find(':') {
+                    Some(n) => n,
+                    None => return false,
+                };
+
+                // header field must be nonzero length
+                if colon_posn == 0 {
+                    return false;
+                }
+
+                l_slice[..colon_posn]
+                    .chars()
+                    .all(|x| !matches!(x as usize, y if !(33..=126).contains(&y)))
+            }
+        }
+    }
+}
+
+impl<'a> Iterator for ParagraphStream<'a> {
+    type Item = Result<Paragraph, String>;
+
+    fn next(&mut self) -> Option<Result<Paragraph, String>> {
+        // return a NoFormatLine in an Err; it should immediately be output
+        let noformat = match self.lines.peek() {
+            None => return None,
+            Some(l) => match *l {
+                Line::FormatLine(_) => false,
+                Line::NoFormatLine(_, _) => true,
+            },
+        };
+
+        // found a NoFormatLine, immediately dump it out
+        if noformat {
+            let (s, nm) = self.lines.next().unwrap().get_noformatline();
+            self.next_mail = nm;
+            return Some(Err(s));
+        }
+
+        // found a FormatLine, now build a paragraph
+        let mut init_str = String::new();
+        let mut init_end = 0;
+        let mut init_len = 0;
+        let mut indent_str = String::new();
+        let mut indent_end = 0;
+        let mut indent_len = 0;
+        let mut prefix_len = 0;
+        let mut pfxind_end = 0;
+        let mut p_lines = Vec::new();
+
+        let mut in_mail = false;
+        let mut second_done = false; // for when we use crown or tagged mode
+        loop {
+            {
+                // peek ahead
+                // need to explicitly force fl out of scope before we can call self.lines.next()
+                let fl = match self.lines.peek() {
+                    None => break,
+                    Some(l) => match *l {
+                        Line::FormatLine(ref x) => x,
+                        Line::NoFormatLine(..) => break,
+                    },
+                };
+
+                if p_lines.is_empty() {
+                    // first time through the loop, get things set up
+                    // detect mail header
+                    if self.opts.mail && self.next_mail && ParagraphStream::is_mail_header(fl) {
+                        in_mail = true;
+                        // there can't be any indent or pfxind because otherwise is_mail_header
+                        // would fail since there cannot be any whitespace before the colon in a
+                        // valid header field
+                        indent_str.push_str("  ");
+                        indent_len = 2;
+                    } else {
+                        if self.opts.crown || self.opts.tagged {
+                            init_str.push_str(&fl.line[..fl.indent_end]);
+                            init_len = fl.indent_len;
+                            init_end = fl.indent_end;
+                        } else {
+                            second_done = true;
+                        }
+
+                        // these will be overwritten in the 2nd line of crown or tagged mode, but
+                        // we are not guaranteed to get to the 2nd line, e.g., if the next line
+                        // is a NoFormatLine or None. Thus, we set sane defaults the 1st time around
+                        indent_str.push_str(&fl.line[..fl.indent_end]);
+                        indent_len = fl.indent_len;
+                        indent_end = fl.indent_end;
+
+                        // save these to check for matching lines
+                        prefix_len = fl.prefix_len;
+                        pfxind_end = fl.pfxind_end;
+
+                        // in tagged mode, add 4 spaces of additional indenting by default
+                        // (gnu fmt's behavior is different: it seems to find the closest column to
+                        // indent_end that is divisible by 3. But honestly that behavior seems
+                        // pretty arbitrary.
+                        // Perhaps a better default would be 1 TABWIDTH? But ugh that's so big.
+                        if self.opts.tagged {
+                            indent_str.push_str("    ");
+                            indent_len += 4;
+                        }
+                    }
+                } else if in_mail {
+                    // lines following mail headers must begin with spaces
+                    if fl.indent_end == 0 || (self.opts.use_prefix && fl.pfxind_end == 0) {
+                        break; // this line does not begin with spaces
+                    }
+                } else if !second_done {
+                    // now we have enough info to handle crown margin and tagged mode
+
+                    // in both crown and tagged modes we require that prefix_len is the same
+                    if prefix_len != fl.prefix_len || pfxind_end != fl.pfxind_end {
+                        break;
+                    }
+
+                    // in tagged mode, indent has to be *different* on following lines
+                    if self.opts.tagged
+                        && indent_len - 4 == fl.indent_len
+                        && indent_end == fl.indent_end
+                    {
+                        break;
+                    }
+
+                    // this is part of the same paragraph, get the indent info from this line
+                    indent_str.clear();
+                    indent_str.push_str(&fl.line[..fl.indent_end]);
+                    indent_len = fl.indent_len;
+                    indent_end = fl.indent_end;
+
+                    second_done = true;
+                } else {
+                    // detect mismatch
+                    if indent_end != fl.indent_end
+                        || pfxind_end != fl.pfxind_end
+                        || indent_len != fl.indent_len
+                        || prefix_len != fl.prefix_len
+                    {
+                        break;
+                    }
+                }
+            }
+
+            p_lines.push(self.lines.next().unwrap().get_formatline().line);
+
+            // when we're in split-only mode, we never join lines, so stop here
+            if self.opts.split_only {
+                break;
+            }
+        }
+
+        // if this was a mail header, then the next line can be detected as one. Otherwise, it cannot.
+        // NOTE next_mail is true at ParagraphStream instantiation, and is set to true after a blank
+        // NoFormatLine.
+        self.next_mail = in_mail;
+
+        Some(Ok(Paragraph {
+            lines: p_lines,
+            init_str,
+            init_len,
+            init_end,
+            indent_str,
+            indent_len,
+            indent_end,
+            mail_header: in_mail,
+        }))
+    }
+}
+
+pub struct ParaWords<'a> {
+    opts: &'a FmtOptions,
+    para: &'a Paragraph,
+    words: Vec<WordInfo<'a>>,
+}
+
+impl<'a> ParaWords<'a> {
+    pub fn new<'b>(opts: &'b FmtOptions, para: &'b Paragraph) -> ParaWords<'b> {
+        let mut pw = ParaWords {
+            opts,
+            para,
+            words: Vec::new(),
+        };
+        pw.create_words();
+        pw
+    }
+
+    fn create_words(&mut self) {
+        if self.para.mail_header {
+            // no extra spacing for mail headers; always exactly 1 space
+            // safe to trim_start on every line of a mail header, since the
+            // first line is guaranteed not to have any spaces
+            self.words.extend(
+                self.para
+                    .lines
+                    .iter()
+                    .flat_map(|x| x.split_whitespace())
+                    .map(|x| WordInfo {
+                        word: x,
+                        word_start: 0,
+                        word_nchars: x.len(), // OK for mail headers; only ASCII allowed (unicode is escaped)
+                        before_tab: None,
+                        after_tab: 0,
+                        sentence_start: false,
+                        ends_punct: false,
+                        new_line: false,
+                    }),
+            );
+        } else {
+            // first line
+            self.words.extend(if self.opts.crown || self.opts.tagged {
+                // crown and tagged mode has the "init" in the first line, so slice from there
+                WordSplit::new(self.opts, &self.para.lines[0][self.para.init_end..])
+            } else {
+                // otherwise we slice from the indent
+                WordSplit::new(self.opts, &self.para.lines[0][self.para.indent_end..])
+            });
+
+            if self.para.lines.len() > 1 {
+                let indent_end = self.para.indent_end;
+                let opts = self.opts;
+                self.words.extend(
+                    self.para
+                        .lines
+                        .iter()
+                        .skip(1)
+                        .flat_map(|x| WordSplit::new(opts, &x[indent_end..])),
+                );
+            }
+        }
+    }
+
+    pub fn words(&'a self) -> Iter<'a, WordInfo<'a>> {
+        self.words.iter()
+    }
+}
+
+struct WordSplit<'a> {
+    opts: &'a FmtOptions,
+    string: &'a str,
+    length: usize,
+    position: usize,
+    prev_punct: bool,
+}
+
+impl<'a> WordSplit<'a> {
+    fn analyze_tabs(&self, string: &str) -> (Option<usize>, usize, Option<usize>) {
+        // given a string, determine (length before tab) and (printed length after first tab)
+        // if there are no tabs, beforetab = -1 and aftertab is the printed length
+        let mut beforetab = None;
+        let mut aftertab = 0;
+        let mut word_start = None;
+        for (os, c) in string.char_indices() {
+            if !c.is_whitespace() {
+                word_start = Some(os);
+                break;
+            } else if c == '\t' {
+                if beforetab == None {
+                    beforetab = Some(aftertab);
+                    aftertab = 0;
+                } else {
+                    aftertab = (aftertab / self.opts.tabwidth + 1) * self.opts.tabwidth;
+                }
+            } else {
+                aftertab += 1;
+            }
+        }
+        (beforetab, aftertab, word_start)
+    }
+}
+
+impl<'a> WordSplit<'a> {
+    fn new<'b>(opts: &'b FmtOptions, string: &'b str) -> WordSplit<'b> {
+        // wordsplits *must* start at a non-whitespace character
+        let trim_string = string.trim_start();
+        WordSplit {
+            opts,
+            string: trim_string,
+            length: string.len(),
+            position: 0,
+            prev_punct: false,
+        }
+    }
+
+    fn is_punctuation(c: char) -> bool {
+        matches!(c, '!' | '.' | '?')
+    }
+}
+
+pub struct WordInfo<'a> {
+    pub word: &'a str,
+    pub word_start: usize,
+    pub word_nchars: usize,
+    pub before_tab: Option<usize>,
+    pub after_tab: usize,
+    pub sentence_start: bool,
+    pub ends_punct: bool,
+    pub new_line: bool,
+}
+
+// returns (&str, is_start_of_sentence)
+impl<'a> Iterator for WordSplit<'a> {
+    type Item = WordInfo<'a>;
+
+    fn next(&mut self) -> Option<WordInfo<'a>> {
+        if self.position >= self.length {
+            return None;
+        }
+
+        let old_position = self.position;
+        let new_line = old_position == 0;
+
+        // find the start of the next word, and record if we find a tab character
+        let (before_tab, after_tab, word_start) =
+            match self.analyze_tabs(&self.string[old_position..]) {
+                (b, a, Some(s)) => (b, a, s + old_position),
+                (_, _, None) => {
+                    self.position = self.length;
+                    return None;
+                }
+            };
+
+        // find the beginning of the next whitespace
+        // note that this preserves the invariant that self.position
+        // points to whitespace character OR end of string
+        let mut word_nchars = 0;
+        self.position = match self.string[word_start..].find(|x: char| {
+            if !x.is_whitespace() {
+                word_nchars += char_width(x);
+                false
+            } else {
+                true
+            }
+        }) {
+            None => self.length,
+            Some(s) => s + word_start,
+        };
+
+        let word_start_relative = word_start - old_position;
+        // if the previous sentence was punctuation and this sentence has >2 whitespace or one tab, is a new sentence.
+        let is_start_of_sentence =
+            self.prev_punct && (before_tab.is_some() || word_start_relative > 1);
+
+        // now record whether this word ends in punctuation
+        self.prev_punct = match self.string[..self.position].chars().rev().next() {
+            Some(ch) => WordSplit::is_punctuation(ch),
+            _ => panic!("fatal: expected word not to be empty"),
+        };
+
+        let (word, word_start_relative, before_tab, after_tab) = if self.opts.uniform {
+            (&self.string[word_start..self.position], 0, None, 0)
+        } else {
+            (
+                &self.string[old_position..self.position],
+                word_start_relative,
+                before_tab,
+                after_tab,
+            )
+        };
+
+        Some(WordInfo {
+            word,
+            word_start: word_start_relative,
+            word_nchars,
+            before_tab,
+            after_tab,
+            sentence_start: is_start_of_sentence,
+            ends_punct: self.prev_punct,
+            new_line,
+        })
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_fold/fold.rs.html b/src/uu_fold/fold.rs.html new file mode 100644 index 000000000..55ddce9a7 --- /dev/null +++ b/src/uu_fold/fold.rs.html @@ -0,0 +1,573 @@ +fold.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDOs) ncount routput
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{stdin, BufRead, BufReader, Read};
+use std::path::Path;
+use uucore::InvalidEncodingHandling;
+
+const TAB_WIDTH: usize = 8;
+
+static NAME: &str = "fold";
+static SYNTAX: &str = "[OPTION]... [FILE]...";
+static SUMMARY: &str = "Writes each file (or standard input if no files are given)
+ to standard output whilst breaking long lines";
+
+mod options {
+    pub const BYTES: &str = "bytes";
+    pub const SPACES: &str = "spaces";
+    pub const WIDTH: &str = "width";
+    pub const FILE: &str = "file";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let (args, obs_width) = handle_obsolete(&args[..]);
+    let matches = uu_app().get_matches_from(args);
+
+    let bytes = matches.is_present(options::BYTES);
+    let spaces = matches.is_present(options::SPACES);
+    let poss_width = match matches.value_of(options::WIDTH) {
+        Some(v) => Some(v.to_owned()),
+        None => obs_width,
+    };
+
+    let width = match poss_width {
+        Some(inp_width) => match inp_width.parse::<usize>() {
+            Ok(width) => width,
+            Err(e) => crash!(1, "illegal width value (\"{}\"): {}", inp_width, e),
+        },
+        None => 80,
+    };
+
+    let files = match matches.values_of(options::FILE) {
+        Some(v) => v.map(|v| v.to_owned()).collect(),
+        None => vec!["-".to_owned()],
+    };
+
+    fold(files, bytes, spaces, width);
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(SYNTAX)
+        .about(SUMMARY)
+        .arg(
+            Arg::with_name(options::BYTES)
+                .long(options::BYTES)
+                .short("b")
+                .help(
+                    "count using bytes rather than columns (meaning control characters \
+                     such as newline are not treated specially)",
+                )
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::SPACES)
+                .long(options::SPACES)
+                .short("s")
+                .help("break lines at word boundaries rather than a hard cut-off")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::WIDTH)
+                .long(options::WIDTH)
+                .short("w")
+                .help("set WIDTH as the maximum line width rather than 80")
+                .value_name("WIDTH")
+                .allow_hyphen_values(true)
+                .takes_value(true),
+        )
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+}
+
+fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
+    for (i, arg) in args.iter().enumerate() {
+        let slice = &arg;
+        if slice.starts_with('-') && slice.chars().nth(1).map_or(false, |c| c.is_digit(10)) {
+            let mut v = args.to_vec();
+            v.remove(i);
+            return (v, Some(slice[1..].to_owned()));
+        }
+    }
+    (args.to_vec(), None)
+}
+
+fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: usize) {
+    for filename in &filenames {
+        let filename: &str = filename;
+        let mut stdin_buf;
+        let mut file_buf;
+        let buffer = BufReader::new(if filename == "-" {
+            stdin_buf = stdin();
+            &mut stdin_buf as &mut dyn Read
+        } else {
+            file_buf = safe_unwrap!(File::open(Path::new(filename)));
+            &mut file_buf as &mut dyn Read
+        });
+
+        if bytes {
+            fold_file_bytewise(buffer, spaces, width);
+        } else {
+            fold_file(buffer, spaces, width);
+        }
+    }
+}
+
+/// Fold `file` to fit `width` (number of columns), counting all characters as
+/// one column.
+///
+/// This function handles folding for the `-b`/`--bytes` option, counting
+/// tab, backspace, and carriage return as occupying one column, identically
+/// to all other characters in the stream.
+///
+///  If `spaces` is `true`, attempt to break lines at whitespace boundaries.
+fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) {
+    let mut line = String::new();
+
+    loop {
+        if let Ok(0) = file.read_line(&mut line) {
+            break;
+        }
+
+        if line == "\n" {
+            println!();
+            line.truncate(0);
+            continue;
+        }
+
+        let len = line.len();
+        let mut i = 0;
+
+        while i < len {
+            let width = if len - i >= width { width } else { len - i };
+            let slice = {
+                let slice = &line[i..i + width];
+                if spaces && i + width < len {
+                    match slice.rfind(|c: char| c.is_whitespace() && c != '\r') {
+                        Some(m) => &slice[..=m],
+                        None => slice,
+                    }
+                } else {
+                    slice
+                }
+            };
+
+            // Don't duplicate trailing newlines: if the slice is "\n", the
+            // previous iteration folded just before the end of the line and
+            // has already printed this newline.
+            if slice == "\n" {
+                break;
+            }
+
+            i += slice.len();
+
+            let at_eol = i >= len;
+
+            if at_eol {
+                print!("{}", slice);
+            } else {
+                println!("{}", slice);
+            }
+        }
+
+        line.truncate(0);
+    }
+}
+
+/// Fold `file` to fit `width` (number of columns).
+///
+/// By default `fold` treats tab, backspace, and carriage return specially:
+/// tab characters count as 8 columns, backspace decreases the
+/// column count, and carriage return resets the column count to 0.
+///
+/// If `spaces` is `true`, attempt to break lines at whitespace boundaries.
+#[allow(unused_assignments)]
+fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) {
+    let mut line = String::new();
+    let mut output = String::new();
+    let mut col_count = 0;
+    let mut last_space = None;
+
+    /// Print the output line, resetting the column and character counts.
+    ///
+    /// If `spaces` is `true`, print the output line up to the last
+    /// encountered whitespace character (inclusive) and set the remaining
+    /// characters as the start of the next line.
+    macro_rules! emit_output {
+        () => {
+            let consume = match last_space {
+                Some(i) => i + 1,
+                None => output.len(),
+            };
+
+            println!("{}", &output[..consume]);
+            output.replace_range(..consume, "");
+
+            // we know there are no tabs left in output, so each char counts
+            // as 1 column
+            col_count = output.len();
+
+            last_space = None;
+        };
+    }
+
+    loop {
+        if let Ok(0) = file.read_line(&mut line) {
+            break;
+        }
+
+        for ch in line.chars() {
+            if ch == '\n' {
+                // make sure to _not_ split output at whitespace, since we
+                // know the entire output will fit
+                last_space = None;
+                emit_output!();
+                break;
+            }
+
+            if col_count >= width {
+                emit_output!();
+            }
+
+            match ch {
+                '\r' => col_count = 0,
+                '\t' => {
+                    let next_tab_stop = col_count + TAB_WIDTH - col_count % TAB_WIDTH;
+
+                    if next_tab_stop > width && !output.is_empty() {
+                        emit_output!();
+                    }
+
+                    col_count = next_tab_stop;
+                    last_space = if spaces { Some(output.len()) } else { None };
+                }
+                '\x08' => {
+                    if col_count > 0 {
+                        col_count -= 1;
+                    }
+                }
+                _ if spaces && ch.is_whitespace() => {
+                    last_space = Some(output.len());
+                    col_count += 1;
+                }
+                _ => col_count += 1,
+            };
+
+            output.push(ch);
+        }
+
+        if !output.is_empty() {
+            print!("{}", output);
+            output.truncate(0);
+        }
+
+        line.truncate(0);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_groups/groups.rs.html b/src/uu_groups/groups.rs.html new file mode 100644 index 000000000..fe3ed6402 --- /dev/null +++ b/src/uu_groups/groups.rs.html @@ -0,0 +1,199 @@ +groups.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Alan Andrade <alan.andradec@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+//
+// ============================================================================
+// Test suite summary for GNU coreutils 8.32.162-4eda
+// ============================================================================
+// PASS: tests/misc/groups-dash.sh
+// PASS: tests/misc/groups-process-all.sh
+// PASS: tests/misc/groups-version.sh
+
+// spell-checker:ignore (ToDO) passwd
+
+#[macro_use]
+extern crate uucore;
+use uucore::entries::{get_groups_gnu, gid2grp, Locate, Passwd};
+
+use clap::{crate_version, App, Arg};
+
+mod options {
+    pub const USERS: &str = "USERNAME";
+}
+static ABOUT: &str = "Print group memberships for each USERNAME or, \
+                      if no USERNAME is specified, for\nthe current process \
+                      (which may differ if the groups data‐base has changed).";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [USERNAME]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let users: Vec<String> = matches
+        .values_of(options::USERS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let mut exit_code = 0;
+
+    if users.is_empty() {
+        println!(
+            "{}",
+            get_groups_gnu(None)
+                .unwrap()
+                .iter()
+                .map(|&gid| gid2grp(gid).unwrap_or_else(|_| {
+                    show_error!("cannot find name for group ID {}", gid);
+                    exit_code = 1;
+                    gid.to_string()
+                }))
+                .collect::<Vec<_>>()
+                .join(" ")
+        );
+        return exit_code;
+    }
+
+    for user in users {
+        if let Ok(p) = Passwd::locate(user.as_str()) {
+            println!(
+                "{} : {}",
+                user,
+                p.belongs_to()
+                    .iter()
+                    .map(|&gid| gid2grp(gid).unwrap_or_else(|_| {
+                        show_error!("cannot find name for group ID {}", gid);
+                        exit_code = 1;
+                        gid.to_string()
+                    }))
+                    .collect::<Vec<_>>()
+                    .join(" ")
+            );
+        } else {
+            show_error!("'{}': no such user", user);
+            exit_code = 1;
+        }
+    }
+    exit_code
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::USERS)
+                .multiple(true)
+                .takes_value(true)
+                .value_name(options::USERS),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_hashsum/digest.rs.html b/src/uu_hashsum/digest.rs.html new file mode 100644 index 000000000..9570a88f7 --- /dev/null +++ b/src/uu_hashsum/digest.rs.html @@ -0,0 +1,325 @@ +digest.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+
+extern crate digest;
+extern crate md5;
+extern crate sha1;
+extern crate sha2;
+extern crate sha3;
+
+use hex::ToHex;
+
+use crate::digest::digest::{ExtendableOutput, Input, XofReader};
+
+pub trait Digest {
+    fn new() -> Self
+    where
+        Self: Sized;
+    fn input(&mut self, input: &[u8]);
+    fn result(&mut self, out: &mut [u8]);
+    fn reset(&mut self);
+    fn output_bits(&self) -> usize;
+    fn output_bytes(&self) -> usize {
+        (self.output_bits() + 7) / 8
+    }
+    fn result_str(&mut self) -> String {
+        let mut buf: Vec<u8> = vec![0; self.output_bytes()];
+        self.result(&mut buf);
+        buf.to_hex()
+    }
+}
+
+impl Digest for md5::Context {
+    fn new() -> Self {
+        md5::Context::new()
+    }
+
+    fn input(&mut self, input: &[u8]) {
+        self.consume(input)
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        out.copy_from_slice(&*self.compute());
+    }
+
+    fn reset(&mut self) {
+        *self = md5::Context::new();
+    }
+
+    fn output_bits(&self) -> usize {
+        128
+    }
+}
+
+impl Digest for blake2b_simd::State {
+    fn new() -> Self {
+        Self::new()
+    }
+
+    fn input(&mut self, input: &[u8]) {
+        self.update(input);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        let hash_result = &self.finalize();
+        out.copy_from_slice(hash_result.as_bytes());
+    }
+
+    fn reset(&mut self) {
+        *self = Self::new();
+    }
+
+    fn output_bits(&self) -> usize {
+        512
+    }
+}
+
+impl Digest for sha1::Sha1 {
+    fn new() -> Self {
+        sha1::Sha1::new()
+    }
+
+    fn input(&mut self, input: &[u8]) {
+        self.update(input);
+    }
+
+    fn result(&mut self, out: &mut [u8]) {
+        out.copy_from_slice(&self.digest().bytes());
+    }
+
+    fn reset(&mut self) {
+        self.reset();
+    }
+
+    fn output_bits(&self) -> usize {
+        160
+    }
+}
+
+// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
+macro_rules! impl_digest_sha {
+    ($type: ty, $size: expr) => {
+        impl Digest for $type {
+            fn new() -> Self {
+                Self::default()
+            }
+
+            fn input(&mut self, input: &[u8]) {
+                digest::Digest::input(self, input);
+            }
+
+            fn result(&mut self, out: &mut [u8]) {
+                out.copy_from_slice(digest::Digest::result(*self).as_slice());
+            }
+
+            fn reset(&mut self) {
+                *self = Self::new();
+            }
+
+            fn output_bits(&self) -> usize {
+                $size
+            }
+        }
+    };
+}
+
+// Implements the Digest trait for sha2 / sha3 algorithms with variable output
+macro_rules! impl_digest_shake {
+    ($type: ty) => {
+        impl Digest for $type {
+            fn new() -> Self {
+                Self::default()
+            }
+
+            fn input(&mut self, input: &[u8]) {
+                self.process(input);
+            }
+
+            fn result(&mut self, out: &mut [u8]) {
+                self.xof_result().read(out);
+            }
+
+            fn reset(&mut self) {
+                *self = Self::new();
+            }
+
+            fn output_bits(&self) -> usize {
+                0
+            }
+        }
+    };
+}
+
+impl_digest_sha!(sha2::Sha224, 224);
+impl_digest_sha!(sha2::Sha256, 256);
+impl_digest_sha!(sha2::Sha384, 384);
+impl_digest_sha!(sha2::Sha512, 512);
+
+impl_digest_sha!(sha3::Sha3_224, 224);
+impl_digest_sha!(sha3::Sha3_256, 256);
+impl_digest_sha!(sha3::Sha3_384, 384);
+impl_digest_sha!(sha3::Sha3_512, 512);
+impl_digest_shake!(sha3::Shake128);
+impl_digest_shake!(sha3::Shake256);
+
+
\ No newline at end of file diff --git a/src/uu_hashsum/hashsum.rs.html b/src/uu_hashsum/hashsum.rs.html new file mode 100644 index 000000000..e498d44f4 --- /dev/null +++ b/src/uu_hashsum/hashsum.rs.html @@ -0,0 +1,1279 @@ +hashsum.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  * (c) Vsevolod Velichko <torkvemada@sorokdva.net>
+//  * (c) Gil Cottle <gcottle@redtown.org>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) algo, algoname, regexes, nread
+
+#[macro_use]
+extern crate clap;
+
+#[macro_use]
+extern crate uucore;
+
+mod digest;
+
+use self::digest::Digest;
+
+use clap::{App, Arg, ArgMatches};
+use hex::ToHex;
+use md5::Context as Md5;
+use regex::Regex;
+use sha1::Sha1;
+use sha2::{Sha224, Sha256, Sha384, Sha512};
+use sha3::{Sha3_224, Sha3_256, Sha3_384, Sha3_512, Shake128, Shake256};
+use std::cmp::Ordering;
+use std::ffi::{OsStr, OsString};
+use std::fs::File;
+use std::io::{self, stdin, BufRead, BufReader, Read};
+use std::iter;
+use std::num::ParseIntError;
+use std::path::Path;
+
+const NAME: &str = "hashsum";
+
+struct Options {
+    algoname: &'static str,
+    digest: Box<dyn Digest + 'static>,
+    binary: bool,
+    check: bool,
+    tag: bool,
+    status: bool,
+    quiet: bool,
+    strict: bool,
+    warn: bool,
+    output_bits: usize,
+}
+
+fn is_custom_binary(program: &str) -> bool {
+    matches!(
+        program,
+        "md5sum"
+            | "sha1sum"
+            | "sha224sum"
+            | "sha256sum"
+            | "sha384sum"
+            | "sha512sum"
+            | "sha3sum"
+            | "sha3-224sum"
+            | "sha3-256sum"
+            | "sha3-384sum"
+            | "sha3-512sum"
+            | "shake128sum"
+            | "shake256sum"
+            | "b2sum"
+    )
+}
+
+#[allow(clippy::cognitive_complexity)]
+fn detect_algo<'a>(
+    program: &str,
+    matches: &ArgMatches<'a>,
+) -> (&'static str, Box<dyn Digest + 'static>, usize) {
+    let mut alg: Option<Box<dyn Digest>> = None;
+    let mut name: &'static str = "";
+    let mut output_bits = 0;
+    match program {
+        "md5sum" => ("MD5", Box::new(Md5::new()) as Box<dyn Digest>, 128),
+        "sha1sum" => ("SHA1", Box::new(Sha1::new()) as Box<dyn Digest>, 160),
+        "sha224sum" => ("SHA224", Box::new(Sha224::new()) as Box<dyn Digest>, 224),
+        "sha256sum" => ("SHA256", Box::new(Sha256::new()) as Box<dyn Digest>, 256),
+        "sha384sum" => ("SHA384", Box::new(Sha384::new()) as Box<dyn Digest>, 384),
+        "sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<dyn Digest>, 512),
+        "b2sum" => (
+            "BLAKE2",
+            Box::new(blake2b_simd::State::new()) as Box<dyn Digest>,
+            512,
+        ),
+        "sha3sum" => match matches.value_of("bits") {
+            Some(bits_str) => match (bits_str).parse::<usize>() {
+                Ok(224) => (
+                    "SHA3-224",
+                    Box::new(Sha3_224::new()) as Box<dyn Digest>,
+                    224,
+                ),
+                Ok(256) => (
+                    "SHA3-256",
+                    Box::new(Sha3_256::new()) as Box<dyn Digest>,
+                    256,
+                ),
+                Ok(384) => (
+                    "SHA3-384",
+                    Box::new(Sha3_384::new()) as Box<dyn Digest>,
+                    384,
+                ),
+                Ok(512) => (
+                    "SHA3-512",
+                    Box::new(Sha3_512::new()) as Box<dyn Digest>,
+                    512,
+                ),
+                Ok(_) => crash!(
+                    1,
+                    "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"
+                ),
+                Err(err) => crash!(1, "{}", err),
+            },
+            None => crash!(1, "--bits required for SHA3"),
+        },
+        "sha3-224sum" => (
+            "SHA3-224",
+            Box::new(Sha3_224::new()) as Box<dyn Digest>,
+            224,
+        ),
+        "sha3-256sum" => (
+            "SHA3-256",
+            Box::new(Sha3_256::new()) as Box<dyn Digest>,
+            256,
+        ),
+        "sha3-384sum" => (
+            "SHA3-384",
+            Box::new(Sha3_384::new()) as Box<dyn Digest>,
+            384,
+        ),
+        "sha3-512sum" => (
+            "SHA3-512",
+            Box::new(Sha3_512::new()) as Box<dyn Digest>,
+            512,
+        ),
+        "shake128sum" => match matches.value_of("bits") {
+            Some(bits_str) => match (bits_str).parse::<usize>() {
+                Ok(bits) => (
+                    "SHAKE128",
+                    Box::new(Shake128::new()) as Box<dyn Digest>,
+                    bits,
+                ),
+                Err(err) => crash!(1, "{}", err),
+            },
+            None => crash!(1, "--bits required for SHAKE-128"),
+        },
+        "shake256sum" => match matches.value_of("bits") {
+            Some(bits_str) => match (bits_str).parse::<usize>() {
+                Ok(bits) => (
+                    "SHAKE256",
+                    Box::new(Shake256::new()) as Box<dyn Digest>,
+                    bits,
+                ),
+                Err(err) => crash!(1, "{}", err),
+            },
+            None => crash!(1, "--bits required for SHAKE-256"),
+        },
+        _ => {
+            {
+                let mut set_or_crash = |n, val, bits| {
+                    if alg.is_some() {
+                        crash!(1, "You cannot combine multiple hash algorithms!")
+                    };
+                    name = n;
+                    alg = Some(val);
+                    output_bits = bits
+                };
+                if matches.is_present("md5") {
+                    set_or_crash("MD5", Box::new(Md5::new()), 128)
+                }
+                if matches.is_present("sha1") {
+                    set_or_crash("SHA1", Box::new(Sha1::new()), 160)
+                }
+                if matches.is_present("sha224") {
+                    set_or_crash("SHA224", Box::new(Sha224::new()), 224)
+                }
+                if matches.is_present("sha256") {
+                    set_or_crash("SHA256", Box::new(Sha256::new()), 256)
+                }
+                if matches.is_present("sha384") {
+                    set_or_crash("SHA384", Box::new(Sha384::new()), 384)
+                }
+                if matches.is_present("sha512") {
+                    set_or_crash("SHA512", Box::new(Sha512::new()), 512)
+                }
+                if matches.is_present("b2sum") {
+                    set_or_crash("BLAKE2", Box::new(blake2b_simd::State::new()), 512)
+                }
+                if matches.is_present("sha3") {
+                    match matches.value_of("bits") {
+                        Some(bits_str) => match (bits_str).parse::<usize>() {
+                            Ok(224) => set_or_crash(
+                                "SHA3-224",
+                                Box::new(Sha3_224::new()) as Box<dyn Digest>,
+                                224,
+                            ),
+                            Ok(256) => set_or_crash(
+                                "SHA3-256",
+                                Box::new(Sha3_256::new()) as Box<dyn Digest>,
+                                256,
+                            ),
+                            Ok(384) => set_or_crash(
+                                "SHA3-384",
+                                Box::new(Sha3_384::new()) as Box<dyn Digest>,
+                                384,
+                            ),
+                            Ok(512) => set_or_crash(
+                                "SHA3-512",
+                                Box::new(Sha3_512::new()) as Box<dyn Digest>,
+                                512,
+                            ),
+                            Ok(_) => crash!(
+                                1,
+                                "Invalid output size for SHA3 (expected 224, 256, 384, or 512)"
+                            ),
+                            Err(err) => crash!(1, "{}", err),
+                        },
+                        None => crash!(1, "--bits required for SHA3"),
+                    }
+                }
+                if matches.is_present("sha3-224") {
+                    set_or_crash("SHA3-224", Box::new(Sha3_224::new()), 224)
+                }
+                if matches.is_present("sha3-256") {
+                    set_or_crash("SHA3-256", Box::new(Sha3_256::new()), 256)
+                }
+                if matches.is_present("sha3-384") {
+                    set_or_crash("SHA3-384", Box::new(Sha3_384::new()), 384)
+                }
+                if matches.is_present("sha3-512") {
+                    set_or_crash("SHA3-512", Box::new(Sha3_512::new()), 512)
+                }
+                if matches.is_present("shake128") {
+                    match matches.value_of("bits") {
+                        Some(bits_str) => match (bits_str).parse::<usize>() {
+                            Ok(bits) => set_or_crash("SHAKE128", Box::new(Shake128::new()), bits),
+                            Err(err) => crash!(1, "{}", err),
+                        },
+                        None => crash!(1, "--bits required for SHAKE-128"),
+                    }
+                }
+                if matches.is_present("shake256") {
+                    match matches.value_of("bits") {
+                        Some(bits_str) => match (bits_str).parse::<usize>() {
+                            Ok(bits) => set_or_crash("SHAKE256", Box::new(Shake256::new()), bits),
+                            Err(err) => crash!(1, "{}", err),
+                        },
+                        None => crash!(1, "--bits required for SHAKE-256"),
+                    }
+                }
+            }
+            let alg = alg.unwrap_or_else(|| crash!(1, "You must specify hash algorithm!"));
+            (name, alg, output_bits)
+        }
+    }
+}
+
+// TODO: return custom error type
+fn parse_bit_num(arg: &str) -> Result<usize, ParseIntError> {
+    arg.parse()
+}
+
+fn is_valid_bit_num(arg: String) -> Result<(), String> {
+    parse_bit_num(&arg)
+        .map(|_| ())
+        .map_err(|e| format!("{}", e))
+}
+
+pub fn uumain(mut args: impl uucore::Args) -> i32 {
+    // if there is no program name for some reason, default to "hashsum"
+    let program = args.next().unwrap_or_else(|| OsString::from(NAME));
+    let binary_name = Path::new(&program)
+        .file_name()
+        .unwrap_or_else(|| OsStr::new(NAME))
+        .to_string_lossy();
+
+    let args = iter::once(program.clone()).chain(args);
+
+    // Default binary in Windows, text mode otherwise
+    let binary_flag_default = cfg!(windows);
+
+    let app = uu_app(&binary_name);
+
+    // FIXME: this should use get_matches_from_safe() and crash!(), but at the moment that just
+    //        causes "error: " to be printed twice (once from crash!() and once from clap).  With
+    //        the current setup, the name of the utility is not printed, but I think this is at
+    //        least somewhat better from a user's perspective.
+    let matches = app.get_matches_from(args);
+
+    let (name, algo, bits) = detect_algo(&binary_name, &matches);
+
+    let binary = if matches.is_present("binary") {
+        true
+    } else if matches.is_present("text") {
+        false
+    } else {
+        binary_flag_default
+    };
+    let check = matches.is_present("check");
+    let tag = matches.is_present("tag");
+    let status = matches.is_present("status");
+    let quiet = matches.is_present("quiet") || status;
+    let strict = matches.is_present("strict");
+    let warn = matches.is_present("warn") && !status;
+
+    let opts = Options {
+        algoname: name,
+        digest: algo,
+        output_bits: bits,
+        binary,
+        check,
+        tag,
+        status,
+        quiet,
+        strict,
+        warn,
+    };
+
+    let res = match matches.values_of_os("FILE") {
+        Some(files) => hashsum(opts, files),
+        None => hashsum(opts, iter::once(OsStr::new("-"))),
+    };
+
+    match res {
+        Ok(()) => 0,
+        Err(e) => e,
+    }
+}
+
+pub fn uu_app_common() -> App<'static, 'static> {
+    #[cfg(windows)]
+    const BINARY_HELP: &str = "read in binary mode (default)";
+    #[cfg(not(windows))]
+    const BINARY_HELP: &str = "read in binary mode";
+    #[cfg(windows)]
+    const TEXT_HELP: &str = "read in text mode";
+    #[cfg(not(windows))]
+    const TEXT_HELP: &str = "read in text mode (default)";
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about("Compute and check message digests.")
+        .arg(
+            Arg::with_name("binary")
+                .short("b")
+                .long("binary")
+                .help(BINARY_HELP),
+        )
+        .arg(
+            Arg::with_name("check")
+                .short("c")
+                .long("check")
+                .help("read hashsums from the FILEs and check them"),
+        )
+        .arg(
+            Arg::with_name("tag")
+                .long("tag")
+                .help("create a BSD-style checksum"),
+        )
+        .arg(
+            Arg::with_name("text")
+                .short("t")
+                .long("text")
+                .help(TEXT_HELP)
+                .conflicts_with("binary"),
+        )
+        .arg(
+            Arg::with_name("quiet")
+                .short("q")
+                .long("quiet")
+                .help("don't print OK for each successfully verified file"),
+        )
+        .arg(
+            Arg::with_name("status")
+                .short("s")
+                .long("status")
+                .help("don't output anything, status code shows success"),
+        )
+        .arg(
+            Arg::with_name("strict")
+                .long("strict")
+                .help("exit non-zero for improperly formatted checksum lines"),
+        )
+        .arg(
+            Arg::with_name("warn")
+                .short("w")
+                .long("warn")
+                .help("warn about improperly formatted checksum lines"),
+        )
+        // Needed for variable-length output sums (e.g. SHAKE)
+        .arg(
+            Arg::with_name("bits")
+                .long("bits")
+                .help("set the size of the output (only for SHAKE)")
+                .takes_value(true)
+                .value_name("BITS")
+                // XXX: should we actually use validators?  they're not particularly efficient
+                .validator(is_valid_bit_num),
+        )
+        .arg(
+            Arg::with_name("FILE")
+                .index(1)
+                .multiple(true)
+                .value_name("FILE"),
+        )
+}
+
+pub fn uu_app_custom() -> App<'static, 'static> {
+    let mut app = uu_app_common();
+    let algorithms = &[
+        ("md5", "work with MD5"),
+        ("sha1", "work with SHA1"),
+        ("sha224", "work with SHA224"),
+        ("sha256", "work with SHA256"),
+        ("sha384", "work with SHA384"),
+        ("sha512", "work with SHA512"),
+        ("sha3", "work with SHA3"),
+        ("sha3-224", "work with SHA3-224"),
+        ("sha3-256", "work with SHA3-256"),
+        ("sha3-384", "work with SHA3-384"),
+        ("sha3-512", "work with SHA3-512"),
+        (
+            "shake128",
+            "work with SHAKE128 using BITS for the output size",
+        ),
+        (
+            "shake256",
+            "work with SHAKE256 using BITS for the output size",
+        ),
+        ("b2sum", "work with BLAKE2"),
+    ];
+
+    for (name, desc) in algorithms {
+        app = app.arg(Arg::with_name(name).long(name).help(desc));
+    }
+    app
+}
+
+// hashsum is handled differently in build.rs, therefore this is not the same
+// as in other utilities.
+fn uu_app(binary_name: &str) -> App<'static, 'static> {
+    if !is_custom_binary(binary_name) {
+        uu_app_custom()
+    } else {
+        uu_app_common()
+    }
+}
+
+#[allow(clippy::cognitive_complexity)]
+fn hashsum<'a, I>(mut options: Options, files: I) -> Result<(), i32>
+where
+    I: Iterator<Item = &'a OsStr>,
+{
+    let mut bad_format = 0;
+    let mut failed = 0;
+    let binary_marker = if options.binary { "*" } else { " " };
+    for filename in files {
+        let filename = Path::new(filename);
+
+        let stdin_buf;
+        let file_buf;
+        let mut file = BufReader::new(if filename == OsStr::new("-") {
+            stdin_buf = stdin();
+            Box::new(stdin_buf) as Box<dyn Read>
+        } else {
+            file_buf = safe_unwrap!(File::open(filename));
+            Box::new(file_buf) as Box<dyn Read>
+        });
+        if options.check {
+            // Set up Regexes for line validation and parsing
+            //
+            // First, we compute the number of bytes we expect to be in
+            // the digest string. If the algorithm has a variable number
+            // of output bits, then we use the `+` modifier in the
+            // regular expression, otherwise we use the `{n}` modifier,
+            // where `n` is the number of bytes.
+            let bytes = options.digest.output_bits() / 4;
+            let modifier = if bytes > 0 {
+                format!("{{{}}}", bytes)
+            } else {
+                "+".to_string()
+            };
+            let gnu_re = safe_unwrap!(Regex::new(&format!(
+                r"^(?P<digest>[a-fA-F0-9]{}) (?P<binary>[ \*])(?P<fileName>.*)",
+                modifier,
+            )));
+            let bsd_re = safe_unwrap!(Regex::new(&format!(
+                r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{digest_size})",
+                algorithm = options.algoname,
+                digest_size = modifier,
+            )));
+
+            let buffer = file;
+            for (i, line) in buffer.lines().enumerate() {
+                let line = safe_unwrap!(line);
+                let (ck_filename, sum, binary_check) = match gnu_re.captures(&line) {
+                    Some(caps) => (
+                        caps.name("fileName").unwrap().as_str(),
+                        caps.name("digest").unwrap().as_str().to_ascii_lowercase(),
+                        caps.name("binary").unwrap().as_str() == "*",
+                    ),
+                    None => match bsd_re.captures(&line) {
+                        Some(caps) => (
+                            caps.name("fileName").unwrap().as_str(),
+                            caps.name("digest").unwrap().as_str().to_ascii_lowercase(),
+                            true,
+                        ),
+                        None => {
+                            bad_format += 1;
+                            if options.strict {
+                                return Err(1);
+                            }
+                            if options.warn {
+                                show_warning!(
+                                    "{}: {}: improperly formatted {} checksum line",
+                                    filename.display(),
+                                    i + 1,
+                                    options.algoname
+                                );
+                            }
+                            continue;
+                        }
+                    },
+                };
+                let f = safe_unwrap!(File::open(ck_filename));
+                let mut ckf = BufReader::new(Box::new(f) as Box<dyn Read>);
+                let real_sum = safe_unwrap!(digest_reader(
+                    &mut *options.digest,
+                    &mut ckf,
+                    binary_check,
+                    options.output_bits
+                ))
+                .to_ascii_lowercase();
+                if sum == real_sum {
+                    if !options.quiet {
+                        println!("{}: OK", ck_filename);
+                    }
+                } else {
+                    if !options.status {
+                        println!("{}: FAILED", ck_filename);
+                    }
+                    failed += 1;
+                }
+            }
+        } else {
+            let sum = safe_unwrap!(digest_reader(
+                &mut *options.digest,
+                &mut file,
+                options.binary,
+                options.output_bits
+            ));
+            if options.tag {
+                println!("{} ({}) = {}", options.algoname, filename.display(), sum);
+            } else {
+                println!("{} {}{}", sum, binary_marker, filename.display());
+            }
+        }
+    }
+    if !options.status {
+        match bad_format.cmp(&1) {
+            Ordering::Equal => show_warning!("{} line is improperly formatted", bad_format),
+            Ordering::Greater => show_warning!("{} lines are improperly formatted", bad_format),
+            _ => {}
+        };
+        if failed > 0 {
+            show_warning!("{} computed checksum did NOT match", failed);
+        }
+    }
+
+    Ok(())
+}
+
+fn digest_reader<'a, T: Read>(
+    digest: &mut (dyn Digest + 'a),
+    reader: &mut BufReader<T>,
+    binary: bool,
+    output_bits: usize,
+) -> io::Result<String> {
+    digest.reset();
+
+    // Digest file, do not hold too much in memory at any given moment
+    let windows = cfg!(windows);
+    let mut buffer = Vec::with_capacity(524_288);
+    let mut vec = Vec::with_capacity(524_288);
+    let mut looking_for_newline = false;
+    loop {
+        match reader.read_to_end(&mut buffer) {
+            Ok(0) => {
+                break;
+            }
+            Ok(nread) => {
+                if windows && !binary {
+                    // Windows text mode returns '\n' when reading '\r\n'
+                    for &b in buffer.iter().take(nread) {
+                        if looking_for_newline {
+                            if b != b'\n' {
+                                vec.push(b'\r');
+                            }
+                            if b != b'\r' {
+                                vec.push(b);
+                                looking_for_newline = false;
+                            }
+                        } else if b != b'\r' {
+                            vec.push(b);
+                        } else {
+                            looking_for_newline = true;
+                        }
+                    }
+                    digest.input(&vec);
+                    vec.clear();
+                } else {
+                    digest.input(&buffer[..nread]);
+                }
+            }
+            Err(e) => return Err(e),
+        }
+    }
+    if windows && looking_for_newline {
+        vec.push(b'\r');
+        digest.input(&vec);
+    }
+
+    if digest.output_bits() > 0 {
+        Ok(digest.result_str())
+    } else {
+        // Assume it's SHAKE.  result_str() doesn't work with shake (as of 8/30/2016)
+        let mut bytes = Vec::new();
+        bytes.resize((output_bits + 7) / 8, 0);
+        digest.result(&mut bytes);
+        Ok(bytes.to_hex())
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_head/head.rs.html b/src/uu_head/head.rs.html new file mode 100644 index 000000000..988ab502b --- /dev/null +++ b/src/uu_head/head.rs.html @@ -0,0 +1,1217 @@ +head.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (vars) zlines
+
+use clap::{crate_version, App, Arg};
+use std::convert::TryFrom;
+use std::ffi::OsString;
+use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
+use uucore::{crash, show_error_custom_description};
+
+const EXIT_FAILURE: i32 = 1;
+const EXIT_SUCCESS: i32 = 0;
+const BUF_SIZE: usize = 65536;
+
+const ABOUT: &str = "\
+                     Print the first 10 lines of each FILE to standard output.\n\
+                     With more than one FILE, precede each with a header giving the file name.\n\
+                     \n\
+                     With no FILE, or when FILE is -, read standard input.\n\
+                     \n\
+                     Mandatory arguments to long flags are mandatory for short flags too.\
+                     ";
+const USAGE: &str = "head [FLAG]... [FILE]...";
+
+mod options {
+    pub const BYTES_NAME: &str = "BYTES";
+    pub const LINES_NAME: &str = "LINES";
+    pub const QUIET_NAME: &str = "QUIET";
+    pub const VERBOSE_NAME: &str = "VERBOSE";
+    pub const ZERO_NAME: &str = "ZERO";
+    pub const FILES_NAME: &str = "FILE";
+}
+mod lines;
+mod parse;
+mod split;
+mod take;
+use lines::zlines;
+use take::take_all_but;
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .usage(USAGE)
+        .arg(
+            Arg::with_name(options::BYTES_NAME)
+                .short("c")
+                .long("bytes")
+                .value_name("[-]NUM")
+                .takes_value(true)
+                .help(
+                    "\
+                     print the first NUM bytes of each file;\n\
+                     with the leading '-', print all but the last\n\
+                     NUM bytes of each file\
+                     ",
+                )
+                .overrides_with_all(&[options::BYTES_NAME, options::LINES_NAME])
+                .allow_hyphen_values(true),
+        )
+        .arg(
+            Arg::with_name(options::LINES_NAME)
+                .short("n")
+                .long("lines")
+                .value_name("[-]NUM")
+                .takes_value(true)
+                .help(
+                    "\
+                     print the first NUM lines instead of the first 10;\n\
+                     with the leading '-', print all but the last\n\
+                     NUM lines of each file\
+                     ",
+                )
+                .overrides_with_all(&[options::LINES_NAME, options::BYTES_NAME])
+                .allow_hyphen_values(true),
+        )
+        .arg(
+            Arg::with_name(options::QUIET_NAME)
+                .short("q")
+                .long("quiet")
+                .visible_alias("silent")
+                .help("never print headers giving file names")
+                .overrides_with_all(&[options::VERBOSE_NAME, options::QUIET_NAME]),
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE_NAME)
+                .short("v")
+                .long("verbose")
+                .help("always print headers giving file names")
+                .overrides_with_all(&[options::QUIET_NAME, options::VERBOSE_NAME]),
+        )
+        .arg(
+            Arg::with_name(options::ZERO_NAME)
+                .short("z")
+                .long("zero-terminated")
+                .help("line delimiter is NUL, not newline")
+                .overrides_with(options::ZERO_NAME),
+        )
+        .arg(Arg::with_name(options::FILES_NAME).multiple(true))
+}
+#[derive(PartialEq, Debug, Clone, Copy)]
+enum Modes {
+    Lines(usize),
+    Bytes(usize),
+}
+
+fn parse_mode<F>(src: &str, closure: F) -> Result<(Modes, bool), String>
+where
+    F: FnOnce(usize) -> Modes,
+{
+    match parse::parse_num(src) {
+        Ok((n, last)) => Ok((closure(n), last)),
+        Err(e) => Err(e.to_string()),
+    }
+}
+
+fn arg_iterate<'a>(
+    mut args: impl uucore::Args + 'a,
+) -> Result<Box<dyn Iterator<Item = OsString> + 'a>, String> {
+    // argv[0] is always present
+    let first = args.next().unwrap();
+    if let Some(second) = args.next() {
+        if let Some(s) = second.to_str() {
+            match parse::parse_obsolete(s) {
+                Some(Ok(iter)) => Ok(Box::new(vec![first].into_iter().chain(iter).chain(args))),
+                Some(Err(e)) => match e {
+                    parse::ParseError::Syntax => Err(format!("bad argument format: '{}'", s)),
+                    parse::ParseError::Overflow => Err(format!(
+                        "invalid argument: '{}' Value too large for defined datatype",
+                        s
+                    )),
+                },
+                None => Ok(Box::new(vec![first, second].into_iter().chain(args))),
+            }
+        } else {
+            Err("bad argument encoding".to_owned())
+        }
+    } else {
+        Ok(Box::new(vec![first].into_iter()))
+    }
+}
+
+#[derive(Debug, PartialEq)]
+struct HeadOptions {
+    pub quiet: bool,
+    pub verbose: bool,
+    pub zeroed: bool,
+    pub all_but_last: bool,
+    pub mode: Modes,
+    pub files: Vec<String>,
+}
+
+impl HeadOptions {
+    pub fn new() -> HeadOptions {
+        HeadOptions {
+            quiet: false,
+            verbose: false,
+            zeroed: false,
+            all_but_last: false,
+            mode: Modes::Lines(10),
+            files: Vec::new(),
+        }
+    }
+
+    ///Construct options from matches
+    pub fn get_from(args: impl uucore::Args) -> Result<Self, String> {
+        let matches = uu_app().get_matches_from(arg_iterate(args)?);
+
+        let mut options = HeadOptions::new();
+
+        options.quiet = matches.is_present(options::QUIET_NAME);
+        options.verbose = matches.is_present(options::VERBOSE_NAME);
+        options.zeroed = matches.is_present(options::ZERO_NAME);
+
+        let mode_and_from_end = if let Some(v) = matches.value_of(options::BYTES_NAME) {
+            parse_mode(v, Modes::Bytes)
+                .map_err(|err| format!("invalid number of bytes: {}", err))?
+        } else if let Some(v) = matches.value_of(options::LINES_NAME) {
+            parse_mode(v, Modes::Lines)
+                .map_err(|err| format!("invalid number of lines: {}", err))?
+        } else {
+            (Modes::Lines(10), false)
+        };
+
+        options.mode = mode_and_from_end.0;
+        options.all_but_last = mode_and_from_end.1;
+
+        options.files = match matches.values_of(options::FILES_NAME) {
+            Some(v) => v.map(|s| s.to_owned()).collect(),
+            None => vec!["-".to_owned()],
+        };
+        //println!("{:#?}", options);
+        Ok(options)
+    }
+}
+// to make clippy shut up
+impl Default for HeadOptions {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+fn read_n_bytes<R>(input: R, n: usize) -> std::io::Result<()>
+where
+    R: Read,
+{
+    // Read the first `n` bytes from the `input` reader.
+    let mut reader = input.take(n as u64);
+
+    // Write those bytes to `stdout`.
+    let stdout = std::io::stdout();
+    let mut stdout = stdout.lock();
+
+    io::copy(&mut reader, &mut stdout)?;
+
+    Ok(())
+}
+
+fn read_n_lines(input: &mut impl std::io::BufRead, n: usize, zero: bool) -> std::io::Result<()> {
+    if n == 0 {
+        return Ok(());
+    }
+    let stdout = std::io::stdout();
+    let mut stdout = stdout.lock();
+    let mut lines = 0usize;
+    split::walk_lines(input, zero, |e| match e {
+        split::Event::Data(dat) => {
+            stdout.write_all(dat)?;
+            Ok(true)
+        }
+        split::Event::Line => {
+            lines += 1;
+            if lines == n {
+                Ok(false)
+            } else {
+                Ok(true)
+            }
+        }
+    })
+}
+
+fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: usize) -> std::io::Result<()> {
+    if n == 0 {
+        //prints everything
+        return read_n_bytes(input, std::usize::MAX);
+    }
+    let stdout = std::io::stdout();
+    let mut stdout = stdout.lock();
+
+    let mut ring_buffer = vec![0u8; n];
+
+    // first we fill the ring buffer
+    if let Err(e) = input.read_exact(&mut ring_buffer) {
+        if e.kind() == ErrorKind::UnexpectedEof {
+            return Ok(());
+        } else {
+            return Err(e);
+        }
+    }
+    let mut buffer = [0u8; BUF_SIZE];
+    loop {
+        let read = loop {
+            match input.read(&mut buffer) {
+                Ok(n) => break n,
+                Err(e) => match e.kind() {
+                    ErrorKind::Interrupted => {}
+                    _ => return Err(e),
+                },
+            }
+        };
+        if read == 0 {
+            return Ok(());
+        } else if read >= n {
+            stdout.write_all(&ring_buffer)?;
+            stdout.write_all(&buffer[..read - n])?;
+            for i in 0..n {
+                ring_buffer[i] = buffer[read - n + i];
+            }
+        } else {
+            stdout.write_all(&ring_buffer[..read])?;
+            for i in 0..n - read {
+                ring_buffer[i] = ring_buffer[read + i];
+            }
+            ring_buffer[n - read..].copy_from_slice(&buffer[..read]);
+        }
+    }
+}
+
+fn read_but_last_n_lines(
+    input: impl std::io::BufRead,
+    n: usize,
+    zero: bool,
+) -> std::io::Result<()> {
+    if zero {
+        let stdout = std::io::stdout();
+        let mut stdout = stdout.lock();
+        for bytes in take_all_but(zlines(input), n) {
+            stdout.write_all(&bytes?)?;
+        }
+    } else {
+        for line in take_all_but(input.lines(), n) {
+            println!("{}", line?);
+        }
+    }
+    Ok(())
+}
+
+fn head_backwards_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> {
+    assert!(options.all_but_last);
+    let size = input.seek(SeekFrom::End(0))?;
+    let size = usize::try_from(size).unwrap();
+    match options.mode {
+        Modes::Bytes(n) => {
+            if n >= size {
+                return Ok(());
+            } else {
+                input.seek(SeekFrom::Start(0))?;
+                read_n_bytes(
+                    &mut std::io::BufReader::with_capacity(BUF_SIZE, input),
+                    size - n,
+                )?;
+            }
+        }
+        Modes::Lines(n) => {
+            let mut buffer = [0u8; BUF_SIZE];
+            let buffer = &mut buffer[..BUF_SIZE.min(size)];
+            let mut i = 0usize;
+            let mut lines = 0usize;
+
+            let found = 'o: loop {
+                // the casts here are ok, `buffer.len()` should never be above a few k
+                input.seek(SeekFrom::Current(
+                    -((buffer.len() as i64).min((size - i) as i64)),
+                ))?;
+                input.read_exact(buffer)?;
+                for byte in buffer.iter().rev() {
+                    match byte {
+                        b'\n' if !options.zeroed => {
+                            lines += 1;
+                        }
+                        0u8 if options.zeroed => {
+                            lines += 1;
+                        }
+                        _ => {}
+                    }
+                    // if it were just `n`,
+                    if lines == n + 1 {
+                        break 'o i;
+                    }
+                    i += 1;
+                }
+                if size - i == 0 {
+                    return Ok(());
+                }
+            };
+            input.seek(SeekFrom::Start(0))?;
+            read_n_bytes(
+                &mut std::io::BufReader::with_capacity(BUF_SIZE, input),
+                size - found,
+            )?;
+        }
+    }
+    Ok(())
+}
+
+fn head_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> {
+    if options.all_but_last {
+        head_backwards_file(input, options)
+    } else {
+        match options.mode {
+            Modes::Bytes(n) => {
+                read_n_bytes(&mut std::io::BufReader::with_capacity(BUF_SIZE, input), n)
+            }
+            Modes::Lines(n) => read_n_lines(
+                &mut std::io::BufReader::with_capacity(BUF_SIZE, input),
+                n,
+                options.zeroed,
+            ),
+        }
+    }
+}
+
+fn uu_head(options: &HeadOptions) -> Result<(), u32> {
+    let mut error_count = 0;
+    let mut first = true;
+    for file in &options.files {
+        let res = match file.as_str() {
+            "-" => {
+                if (options.files.len() > 1 && !options.quiet) || options.verbose {
+                    if !first {
+                        println!();
+                    }
+                    println!("==> standard input <==")
+                }
+                let stdin = std::io::stdin();
+                let mut stdin = stdin.lock();
+                match options.mode {
+                    Modes::Bytes(n) => {
+                        if options.all_but_last {
+                            read_but_last_n_bytes(&mut stdin, n)
+                        } else {
+                            read_n_bytes(&mut stdin, n)
+                        }
+                    }
+                    Modes::Lines(n) => {
+                        if options.all_but_last {
+                            read_but_last_n_lines(&mut stdin, n, options.zeroed)
+                        } else {
+                            read_n_lines(&mut stdin, n, options.zeroed)
+                        }
+                    }
+                }
+            }
+            name => {
+                let mut file = match std::fs::File::open(name) {
+                    Ok(f) => f,
+                    Err(err) => {
+                        let prefix = format!("cannot open '{}' for reading", name);
+                        match err.kind() {
+                            ErrorKind::NotFound => {
+                                show_error_custom_description!(prefix, "No such file or directory");
+                            }
+                            ErrorKind::PermissionDenied => {
+                                show_error_custom_description!(prefix, "Permission denied");
+                            }
+                            _ => {
+                                show_error_custom_description!(prefix, "{}", err);
+                            }
+                        }
+                        error_count += 1;
+                        continue;
+                    }
+                };
+                if (options.files.len() > 1 && !options.quiet) || options.verbose {
+                    if !first {
+                        println!();
+                    }
+                    println!("==> {} <==", name)
+                }
+                head_file(&mut file, options)
+            }
+        };
+        if res.is_err() {
+            let name = if file.as_str() == "-" {
+                "standard input"
+            } else {
+                file
+            };
+            let prefix = format!("error reading {}", name);
+            show_error_custom_description!(prefix, "Input/output error");
+            error_count += 1;
+        }
+        first = false;
+    }
+    if error_count > 0 {
+        Err(error_count)
+    } else {
+        Ok(())
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = match HeadOptions::get_from(args) {
+        Ok(o) => o,
+        Err(s) => {
+            crash!(EXIT_FAILURE, "{}", s);
+        }
+    };
+    match uu_head(&args) {
+        Ok(_) => EXIT_SUCCESS,
+        Err(_) => EXIT_FAILURE,
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use std::ffi::OsString;
+
+    use super::*;
+    fn options(args: &str) -> Result<HeadOptions, String> {
+        let combined = "head ".to_owned() + args;
+        let args = combined.split_whitespace();
+        HeadOptions::get_from(args.map(OsString::from))
+    }
+    #[test]
+    fn test_args_modes() {
+        let args = options("-n -10M -vz").unwrap();
+        assert!(args.zeroed);
+        assert!(args.verbose);
+        assert!(args.all_but_last);
+        assert_eq!(args.mode, Modes::Lines(10 * 1024 * 1024));
+    }
+    #[test]
+    fn test_gnu_compatibility() {
+        let args = options("-n 1 -c 1 -n 5 -c kiB -vqvqv").unwrap(); // spell-checker:disable-line
+        assert!(args.mode == Modes::Bytes(1024));
+        assert!(args.verbose);
+        assert_eq!(options("-5").unwrap().mode, Modes::Lines(5));
+        assert_eq!(options("-2b").unwrap().mode, Modes::Bytes(1024));
+        assert_eq!(options("-5 -c 1").unwrap().mode, Modes::Bytes(1));
+    }
+    #[test]
+    fn all_args_test() {
+        assert!(options("--silent").unwrap().quiet);
+        assert!(options("--quiet").unwrap().quiet);
+        assert!(options("-q").unwrap().quiet);
+        assert!(options("--verbose").unwrap().verbose);
+        assert!(options("-v").unwrap().verbose);
+        assert!(options("--zero-terminated").unwrap().zeroed);
+        assert!(options("-z").unwrap().zeroed);
+        assert_eq!(options("--lines 15").unwrap().mode, Modes::Lines(15));
+        assert_eq!(options("-n 15").unwrap().mode, Modes::Lines(15));
+        assert_eq!(options("--bytes 15").unwrap().mode, Modes::Bytes(15));
+        assert_eq!(options("-c 15").unwrap().mode, Modes::Bytes(15));
+    }
+    #[test]
+    fn test_options_errors() {
+        assert!(options("-n IsThisTheRealLife?").is_err());
+        assert!(options("-c IsThisJustFantasy").is_err());
+    }
+    #[test]
+    #[allow(clippy::bool_comparison)]
+    fn test_options_correct_defaults() {
+        let opts = HeadOptions::new();
+        let opts2: HeadOptions = Default::default();
+
+        assert_eq!(opts, opts2);
+
+        assert!(opts.verbose == false);
+        assert!(opts.quiet == false);
+        assert!(opts.zeroed == false);
+        assert!(opts.all_but_last == false);
+        assert_eq!(opts.mode, Modes::Lines(10));
+        assert!(opts.files.is_empty());
+    }
+    #[test]
+    fn test_parse_mode() {
+        assert_eq!(
+            parse_mode("123", Modes::Lines),
+            Ok((Modes::Lines(123), false))
+        );
+        assert_eq!(
+            parse_mode("-456", Modes::Bytes),
+            Ok((Modes::Bytes(456), true))
+        );
+        assert!(parse_mode("Nonsensical Nonsense", Modes::Bytes).is_err());
+        #[cfg(target_pointer_width = "64")]
+        assert!(parse_mode("1Y", Modes::Lines).is_err());
+        #[cfg(target_pointer_width = "32")]
+        assert!(parse_mode("1T", Modes::Bytes).is_err());
+    }
+    fn arg_outputs(src: &str) -> Result<String, String> {
+        let split = src.split_whitespace().map(OsString::from);
+        match arg_iterate(split) {
+            Ok(args) => {
+                let vec = args
+                    .map(|s| s.to_str().unwrap().to_owned())
+                    .collect::<Vec<_>>();
+                Ok(vec.join(" "))
+            }
+            Err(e) => Err(e),
+        }
+    }
+    #[test]
+    fn test_arg_iterate() {
+        // test that normal args remain unchanged
+        assert_eq!(
+            arg_outputs("head -n -5 -zv"),
+            Ok("head -n -5 -zv".to_owned())
+        );
+        // tests that nonsensical args are unchanged
+        assert_eq!(
+            arg_outputs("head -to_be_or_not_to_be,..."),
+            Ok("head -to_be_or_not_to_be,...".to_owned())
+        );
+        //test that the obsolete syntax is unrolled
+        assert_eq!(
+            arg_outputs("head -123qvqvqzc"), // spell-checker:disable-line
+            Ok("head -q -z -c 123".to_owned())
+        );
+        //test that bad obsoletes are an error
+        assert!(arg_outputs("head -123FooBar").is_err());
+        //test overflow
+        assert!(arg_outputs("head -100000000000000000000000000000000000000000").is_err());
+        //test that empty args remain unchanged
+        assert_eq!(arg_outputs("head"), Ok("head".to_owned()));
+    }
+    #[test]
+    #[cfg(target_os = "linux")]
+    fn test_arg_iterate_bad_encoding() {
+        let invalid = unsafe { std::str::from_utf8_unchecked(b"\x80\x81") };
+        // this arises from a conversion from OsString to &str
+        assert!(
+            arg_iterate(vec![OsString::from("head"), OsString::from(invalid)].into_iter()).is_err()
+        );
+    }
+    #[test]
+    fn read_early_exit() {
+        let mut empty = std::io::BufReader::new(std::io::Cursor::new(Vec::new()));
+        assert!(read_n_bytes(&mut empty, 0).is_ok());
+        assert!(read_n_lines(&mut empty, 0, false).is_ok());
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_head/lines.rs.html b/src/uu_head/lines.rs.html new file mode 100644 index 000000000..bf04135a4 --- /dev/null +++ b/src/uu_head/lines.rs.html @@ -0,0 +1,155 @@ +lines.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+
+// spell-checker:ignore (vars) zline zlines
+
+//! Iterate over zero-terminated lines.
+use std::io::BufRead;
+
+/// The zero byte, representing the null character.
+const ZERO: u8 = 0;
+
+/// Returns an iterator over the lines of the given reader.
+///
+/// The iterator returned from this function will yield instances of
+/// [`io::Result`]<[`Vec`]<[`u8`]>>, representing the bytes of the line
+/// *including* the null character (with the possible exception of the
+/// last line, which may not have one).
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// use std::io::Cursor;
+///
+/// let cursor = Cursor::new(b"x\0y\0z\0");
+/// let mut iter = zlines(cursor).map(|l| l.unwrap());
+/// assert_eq!(iter.next(), Some(b"x\0".to_vec()));
+/// assert_eq!(iter.next(), Some(b"y\0".to_vec()));
+/// assert_eq!(iter.next(), Some(b"z\0".to_vec()));
+/// assert_eq!(iter.next(), None);
+/// ```
+pub fn zlines<B>(buf: B) -> ZLines<B> {
+    ZLines { buf }
+}
+
+/// An iterator over the zero-terminated lines of an instance of `BufRead`.
+pub struct ZLines<B> {
+    buf: B,
+}
+
+impl<B: BufRead> Iterator for ZLines<B> {
+    type Item = std::io::Result<Vec<u8>>;
+
+    fn next(&mut self) -> Option<std::io::Result<Vec<u8>>> {
+        let mut buf = Vec::new();
+        match self.buf.read_until(ZERO, &mut buf) {
+            Ok(0) => None,
+            Ok(_) => Some(Ok(buf)),
+            Err(e) => Some(Err(e)),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use crate::lines::zlines;
+    use std::io::Cursor;
+
+    #[test]
+    fn test_null_terminated() {
+        let cursor = Cursor::new(b"x\0y\0z\0");
+        let mut iter = zlines(cursor).map(|l| l.unwrap());
+        assert_eq!(iter.next(), Some(b"x\0".to_vec()));
+        assert_eq!(iter.next(), Some(b"y\0".to_vec()));
+        assert_eq!(iter.next(), Some(b"z\0".to_vec()));
+        assert_eq!(iter.next(), None);
+    }
+
+    #[test]
+    fn test_not_null_terminated() {
+        let cursor = Cursor::new(b"x\0y\0z");
+        let mut iter = zlines(cursor).map(|l| l.unwrap());
+        assert_eq!(iter.next(), Some(b"x\0".to_vec()));
+        assert_eq!(iter.next(), Some(b"y\0".to_vec()));
+        assert_eq!(iter.next(), Some(b"z".to_vec()));
+        assert_eq!(iter.next(), None);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_head/parse.rs.html b/src/uu_head/parse.rs.html new file mode 100644 index 000000000..a8c29f07b --- /dev/null +++ b/src/uu_head/parse.rs.html @@ -0,0 +1,369 @@ +parse.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+use std::ffi::OsString;
+use uucore::parse_size::{parse_size, ParseSizeError};
+
+#[derive(PartialEq, Debug)]
+pub enum ParseError {
+    Syntax,
+    Overflow,
+}
+/// Parses obsolete syntax
+/// head -NUM[kmzv] // spell-checker:disable-line
+pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>, ParseError>> {
+    let mut chars = src.char_indices();
+    if let Some((_, '-')) = chars.next() {
+        let mut num_end = 0usize;
+        let mut has_num = false;
+        let mut last_char = 0 as char;
+        for (n, c) in &mut chars {
+            if c.is_numeric() {
+                has_num = true;
+                num_end = n;
+            } else {
+                last_char = c;
+                break;
+            }
+        }
+        if has_num {
+            match src[1..=num_end].parse::<usize>() {
+                Ok(num) => {
+                    let mut quiet = false;
+                    let mut verbose = false;
+                    let mut zero_terminated = false;
+                    let mut multiplier = None;
+                    let mut c = last_char;
+                    loop {
+                        // not that here, we only match lower case 'k', 'c', and 'm'
+                        match c {
+                            // we want to preserve order
+                            // this also saves us 1 heap allocation
+                            'q' => {
+                                quiet = true;
+                                verbose = false
+                            }
+                            'v' => {
+                                verbose = true;
+                                quiet = false
+                            }
+                            'z' => zero_terminated = true,
+                            'c' => multiplier = Some(1),
+                            'b' => multiplier = Some(512),
+                            'k' => multiplier = Some(1024),
+                            'm' => multiplier = Some(1024 * 1024),
+                            '\0' => {}
+                            _ => return Some(Err(ParseError::Syntax)),
+                        }
+                        if let Some((_, next)) = chars.next() {
+                            c = next
+                        } else {
+                            break;
+                        }
+                    }
+                    let mut options = Vec::new();
+                    if quiet {
+                        options.push(OsString::from("-q"))
+                    }
+                    if verbose {
+                        options.push(OsString::from("-v"))
+                    }
+                    if zero_terminated {
+                        options.push(OsString::from("-z"))
+                    }
+                    if let Some(n) = multiplier {
+                        options.push(OsString::from("-c"));
+                        let num = match num.checked_mul(n) {
+                            Some(n) => n,
+                            None => return Some(Err(ParseError::Overflow)),
+                        };
+                        options.push(OsString::from(format!("{}", num)));
+                    } else {
+                        options.push(OsString::from("-n"));
+                        options.push(OsString::from(format!("{}", num)));
+                    }
+                    Some(Ok(options.into_iter()))
+                }
+                Err(_) => Some(Err(ParseError::Overflow)),
+            }
+        } else {
+            None
+        }
+    } else {
+        None
+    }
+}
+/// Parses an -c or -n argument,
+/// the bool specifies whether to read from the end
+pub fn parse_num(src: &str) -> Result<(usize, bool), ParseSizeError> {
+    let mut size_string = src.trim();
+    let mut all_but_last = false;
+
+    if let Some(c) = size_string.chars().next() {
+        if c == '+' || c == '-' {
+            // head: '+' is not documented (8.32 man pages)
+            size_string = &size_string[1..];
+            if c == '-' {
+                all_but_last = true;
+            }
+        }
+    } else {
+        return Err(ParseSizeError::ParseFailure(src.to_string()));
+    }
+
+    parse_size(size_string).map(|n| (n, all_but_last))
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    fn obsolete(src: &str) -> Option<Result<Vec<String>, ParseError>> {
+        let r = parse_obsolete(src);
+        match r {
+            Some(s) => match s {
+                Ok(v) => Some(Ok(v.map(|s| s.to_str().unwrap().to_owned()).collect())),
+                Err(e) => Some(Err(e)),
+            },
+            None => None,
+        }
+    }
+    fn obsolete_result(src: &[&str]) -> Option<Result<Vec<String>, ParseError>> {
+        Some(Ok(src.iter().map(|s| s.to_string()).collect()))
+    }
+    #[test]
+    fn test_parse_numbers_obsolete() {
+        assert_eq!(obsolete("-5"), obsolete_result(&["-n", "5"]));
+        assert_eq!(obsolete("-100"), obsolete_result(&["-n", "100"]));
+        assert_eq!(obsolete("-5m"), obsolete_result(&["-c", "5242880"]));
+        assert_eq!(obsolete("-1k"), obsolete_result(&["-c", "1024"]));
+        assert_eq!(obsolete("-2b"), obsolete_result(&["-c", "1024"]));
+        assert_eq!(obsolete("-1mmk"), obsolete_result(&["-c", "1024"]));
+        assert_eq!(obsolete("-1vz"), obsolete_result(&["-v", "-z", "-n", "1"]));
+        assert_eq!(
+            obsolete("-1vzqvq"), // spell-checker:disable-line
+            obsolete_result(&["-q", "-z", "-n", "1"])
+        );
+        assert_eq!(obsolete("-1vzc"), obsolete_result(&["-v", "-z", "-c", "1"]));
+        assert_eq!(
+            obsolete("-105kzm"),
+            obsolete_result(&["-z", "-c", "110100480"])
+        );
+    }
+    #[test]
+    fn test_parse_errors_obsolete() {
+        assert_eq!(obsolete("-5n"), Some(Err(ParseError::Syntax)));
+        assert_eq!(obsolete("-5c5"), Some(Err(ParseError::Syntax)));
+    }
+    #[test]
+    fn test_parse_obsolete_no_match() {
+        assert_eq!(obsolete("-k"), None);
+        assert_eq!(obsolete("asd"), None);
+    }
+    #[test]
+    #[cfg(target_pointer_width = "64")]
+    fn test_parse_obsolete_overflow_x64() {
+        assert_eq!(
+            obsolete("-1000000000000000m"),
+            Some(Err(ParseError::Overflow))
+        );
+        assert_eq!(
+            obsolete("-10000000000000000000000"),
+            Some(Err(ParseError::Overflow))
+        );
+    }
+    #[test]
+    #[cfg(target_pointer_width = "32")]
+    fn test_parse_obsolete_overflow_x32() {
+        assert_eq!(obsolete("-42949672960"), Some(Err(ParseError::Overflow)));
+        assert_eq!(obsolete("-42949672k"), Some(Err(ParseError::Overflow)));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_head/split.rs.html b/src/uu_head/split.rs.html new file mode 100644 index 000000000..68775c88b --- /dev/null +++ b/src/uu_head/split.rs.html @@ -0,0 +1,125 @@ +split.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+
+#[derive(Debug)]
+pub enum Event<'a> {
+    Data(&'a [u8]),
+    Line,
+}
+/// Loops over the lines read from a BufRead.
+/// # Arguments
+/// * `input` the ReadBuf to read from
+/// * `zero` whether to use 0u8 as a line delimiter
+/// * `on_event` a closure receiving some bytes read in a slice, or
+///     event signalling a line was just read.
+///     this is guaranteed to be signalled *directly* after the
+///     slice containing the (CR on win)LF / 0 is passed
+///
+///     Return whether to continue
+pub fn walk_lines<F>(
+    input: &mut impl std::io::BufRead,
+    zero: bool,
+    mut on_event: F,
+) -> std::io::Result<()>
+where
+    F: FnMut(Event) -> std::io::Result<bool>,
+{
+    let mut buffer = [0u8; super::BUF_SIZE];
+    loop {
+        let read = loop {
+            match input.read(&mut buffer) {
+                Ok(n) => break n,
+                Err(e) => match e.kind() {
+                    std::io::ErrorKind::Interrupted => {}
+                    _ => return Err(e),
+                },
+            }
+        };
+        if read == 0 {
+            return Ok(());
+        }
+        let mut base = 0usize;
+        for (i, byte) in buffer[..read].iter().enumerate() {
+            match byte {
+                b'\n' if !zero => {
+                    on_event(Event::Data(&buffer[base..=i]))?;
+                    base = i + 1;
+                    if !on_event(Event::Line)? {
+                        return Ok(());
+                    }
+                }
+                0u8 if zero => {
+                    on_event(Event::Data(&buffer[base..=i]))?;
+                    base = i + 1;
+                    if !on_event(Event::Line)? {
+                        return Ok(());
+                    }
+                }
+                _ => {}
+            }
+        }
+        on_event(Event::Data(&buffer[base..read]))?;
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_head/take.rs.html b/src/uu_head/take.rs.html new file mode 100644 index 000000000..1fc333021 --- /dev/null +++ b/src/uu_head/take.rs.html @@ -0,0 +1,191 @@ +take.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+
+//! Take all but the last elements of an iterator.
+use uucore::ringbuffer::RingBuffer;
+
+/// Create an iterator over all but the last `n` elements of `iter`.
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// let data = [1, 2, 3, 4, 5];
+/// let n = 2;
+/// let mut iter = take_all_but(data.iter(), n);
+/// assert_eq!(Some(4), iter.next());
+/// assert_eq!(Some(5), iter.next());
+/// assert_eq!(None, iter.next());
+/// ```
+pub fn take_all_but<I: Iterator>(iter: I, n: usize) -> TakeAllBut<I> {
+    TakeAllBut::new(iter, n)
+}
+
+/// An iterator that only iterates over the last elements of another iterator.
+pub struct TakeAllBut<I: Iterator> {
+    iter: I,
+    buf: RingBuffer<<I as Iterator>::Item>,
+}
+
+impl<I: Iterator> TakeAllBut<I> {
+    pub fn new(mut iter: I, n: usize) -> TakeAllBut<I> {
+        // Create a new ring buffer and fill it up.
+        //
+        // If there are fewer than `n` elements in `iter`, then we
+        // exhaust the iterator so that whenever `TakeAllBut::next()` is
+        // called, it will return `None`, as expected.
+        let mut buf = RingBuffer::new(n);
+        for _ in 0..n {
+            let value = match iter.next() {
+                None => {
+                    break;
+                }
+                Some(x) => x,
+            };
+            buf.push_back(value);
+        }
+        TakeAllBut { iter, buf }
+    }
+}
+
+impl<I: Iterator> Iterator for TakeAllBut<I>
+where
+    I: Iterator,
+{
+    type Item = <I as Iterator>::Item;
+
+    fn next(&mut self) -> Option<<I as Iterator>::Item> {
+        match self.iter.next() {
+            Some(value) => self.buf.push_back(value),
+            None => None,
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use crate::take::take_all_but;
+
+    #[test]
+    fn test_fewer_elements() {
+        let mut iter = take_all_but([0, 1, 2].iter(), 2);
+        assert_eq!(Some(&0), iter.next());
+        assert_eq!(None, iter.next());
+    }
+
+    #[test]
+    fn test_same_number_of_elements() {
+        let mut iter = take_all_but([0, 1].iter(), 2);
+        assert_eq!(None, iter.next());
+    }
+
+    #[test]
+    fn test_more_elements() {
+        let mut iter = take_all_but([0].iter(), 2);
+        assert_eq!(None, iter.next());
+    }
+
+    #[test]
+    fn test_zero_elements() {
+        let mut iter = take_all_but([0, 1, 2].iter(), 0);
+        assert_eq!(Some(&0), iter.next());
+        assert_eq!(Some(&1), iter.next());
+        assert_eq!(Some(&2), iter.next());
+        assert_eq!(None, iter.next());
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_hostid/hostid.rs.html b/src/uu_hostid/hostid.rs.html new file mode 100644 index 000000000..ed2950208 --- /dev/null +++ b/src/uu_hostid/hostid.rs.html @@ -0,0 +1,113 @@ +hostid.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Maciej Dziardziel <fiedzia@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE file
+//  * that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) gethostid
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App};
+use libc::c_long;
+use uucore::error::UResult;
+
+static SYNTAX: &str = "[options]";
+
+// currently rust libc interface doesn't include gethostid
+extern "C" {
+    pub fn gethostid() -> c_long;
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    uu_app().get_matches_from(args);
+    hostid();
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .usage(SYNTAX)
+}
+
+fn hostid() {
+    /*
+     * POSIX says gethostid returns a "32-bit identifier" but is silent
+     * whether it's sign-extended.  Turn off any sign-extension.  This
+     * is a no-op unless unsigned int is wider than 32 bits.
+     */
+
+    let mut result: c_long;
+    unsafe {
+        result = gethostid();
+    }
+
+    #[allow(overflowing_literals)]
+    let mask = 0xffff_ffff;
+
+    result &= mask;
+    println!("{:0>8x}", result);
+}
+
+
\ No newline at end of file diff --git a/src/uu_hostname/hostname.rs.html b/src/uu_hostname/hostname.rs.html new file mode 100644 index 000000000..3d1797959 --- /dev/null +++ b/src/uu_hostname/hostname.rs.html @@ -0,0 +1,323 @@ +hostname.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alan Andrade <alan.andradec@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) MAKEWORD addrs hashset
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use std::collections::hash_set::HashSet;
+use std::net::ToSocketAddrs;
+use std::str;
+#[cfg(windows)]
+use uucore::error::UUsageError;
+use uucore::error::{UResult, USimpleError};
+
+#[cfg(windows)]
+use winapi::shared::minwindef::MAKEWORD;
+#[cfg(windows)]
+use winapi::um::winsock2::{WSACleanup, WSAStartup};
+
+static ABOUT: &str = "Display or set the system's host name.";
+
+static OPT_DOMAIN: &str = "domain";
+static OPT_IP_ADDRESS: &str = "ip-address";
+static OPT_FQDN: &str = "fqdn";
+static OPT_SHORT: &str = "short";
+static OPT_HOST: &str = "host";
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    #![allow(clippy::let_and_return)]
+    #[cfg(windows)]
+    unsafe {
+        #[allow(deprecated)]
+        let mut data = std::mem::uninitialized();
+        if WSAStartup(MAKEWORD(2, 2), &mut data as *mut _) != 0 {
+            return Err(UUsageError::new(
+                1,
+                "Failed to start Winsock 2.2".to_string(),
+            ));
+        }
+    }
+    let result = execute(args);
+    #[cfg(windows)]
+    unsafe {
+        WSACleanup();
+    }
+    result
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [HOSTNAME]", uucore::execution_phrase())
+}
+
+fn execute(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    match matches.value_of(OPT_HOST) {
+        None => display_hostname(&matches),
+        Some(host) => {
+            if let Err(err) = hostname::set(host) {
+                return Err(USimpleError::new(1, format!("{}", err)));
+            } else {
+                Ok(())
+            }
+        }
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_DOMAIN)
+                .short("d")
+                .long("domain")
+                .help("Display the name of the DNS domain if possible"),
+        )
+        .arg(
+            Arg::with_name(OPT_IP_ADDRESS)
+                .short("i")
+                .long("ip-address")
+                .help("Display the network address(es) of the host"),
+        )
+        // TODO: support --long
+        .arg(
+            Arg::with_name(OPT_FQDN)
+                .short("f")
+                .long("fqdn")
+                .help("Display the FQDN (Fully Qualified Domain Name) (default)"),
+        )
+        .arg(Arg::with_name(OPT_SHORT).short("s").long("short").help(
+            "Display the short hostname (the portion before the first dot) if \
+             possible",
+        ))
+        .arg(Arg::with_name(OPT_HOST))
+}
+
+fn display_hostname(matches: &ArgMatches) -> UResult<()> {
+    let hostname = hostname::get().unwrap().into_string().unwrap();
+
+    if matches.is_present(OPT_IP_ADDRESS) {
+        // XXX: to_socket_addrs needs hostname:port so append a dummy port and remove it later.
+        // This was originally supposed to use std::net::lookup_host, but that seems to be
+        // deprecated.  Perhaps we should use the dns-lookup crate?
+        let hostname = hostname + ":1";
+        match hostname.to_socket_addrs() {
+            Ok(addresses) => {
+                let mut hashset = HashSet::new();
+                let mut output = String::new();
+                for addr in addresses {
+                    // XXX: not sure why this is necessary...
+                    if !hashset.contains(&addr) {
+                        let mut ip = format!("{}", addr);
+                        if ip.ends_with(":1") {
+                            let len = ip.len();
+                            ip.truncate(len - 2);
+                        }
+                        output.push_str(&ip);
+                        output.push(' ');
+                        hashset.insert(addr);
+                    }
+                }
+                let len = output.len();
+                if len > 0 {
+                    println!("{}", &output[0..len - 1]);
+                }
+
+                Ok(())
+            }
+            Err(f) => {
+                return Err(USimpleError::new(1, format!("{}", f)));
+            }
+        }
+    } else {
+        if matches.is_present(OPT_SHORT) || matches.is_present(OPT_DOMAIN) {
+            let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.');
+            if let Some(ci) = it.next() {
+                if matches.is_present(OPT_SHORT) {
+                    println!("{}", &hostname[0..ci.0]);
+                } else {
+                    println!("{}", &hostname[ci.0 + 1..]);
+                }
+                return Ok(());
+            }
+        }
+
+        println!("{}", hostname);
+
+        Ok(())
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_id/id.rs.html b/src/uu_id/id.rs.html new file mode 100644 index 000000000..37f764e6b --- /dev/null +++ b/src/uu_id/id.rs.html @@ -0,0 +1,1357 @@ +id.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Alan Andrade <alan.andradec@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) asid auditid auditinfo auid cstr egid emod euid getaudit getlogin gflag nflag pline rflag termid uflag gsflag zflag cflag
+
+// README:
+// This was originally based on BSD's `id`
+// (noticeable in functionality, usage text, options text, etc.)
+// and synced with:
+//  http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c
+//  http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c
+//
+// * This was partially rewritten in order for stdout/stderr/exit_code
+//   to be conform with GNU coreutils (8.32) test suite for `id`.
+//
+// * This supports multiple users (a feature that was introduced in coreutils 8.31)
+//
+// * This passes GNU's coreutils Test suite (8.32)
+//   for "tests/id/uid.sh" and "tests/id/zero/sh".
+//
+// * Option '--zero' does not exist for BSD's `id`, therefore '--zero' is only
+//   allowed together with other options that are available on GNU's `id`.
+//
+// * Help text based on BSD's `id` manpage and GNU's `id` manpage.
+//
+// * This passes GNU's coreutils Test suite (8.32) for "tests/id/context.sh" if compiled with
+//   `--features feat_selinux`. It should also pass "tests/id/no-context.sh", but that depends on
+//   `uu_ls -Z` being implemented and therefore fails at the moment
+//
+
+#![allow(non_camel_case_types)]
+#![allow(dead_code)]
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::ffi::CStr;
+use uucore::entries::{self, Group, Locate, Passwd};
+use uucore::error::UResult;
+use uucore::error::{set_exit_code, USimpleError};
+pub use uucore::libc;
+use uucore::libc::{getlogin, uid_t};
+use uucore::process::{getegid, geteuid, getgid, getuid};
+
+macro_rules! cstr2cow {
+    ($v:expr) => {
+        unsafe { CStr::from_ptr($v).to_string_lossy() }
+    };
+}
+
+static ABOUT: &str = "Print user and group information for each specified USER,
+or (when USER omitted) for the current user.";
+
+#[cfg(not(feature = "selinux"))]
+static CONTEXT_HELP_TEXT: &str = "print only the security context of the process (not enabled)";
+#[cfg(feature = "selinux")]
+static CONTEXT_HELP_TEXT: &str = "print only the security context of the process";
+
+mod options {
+    pub const OPT_AUDIT: &str = "audit"; // GNU's id does not have this
+    pub const OPT_CONTEXT: &str = "context";
+    pub const OPT_EFFECTIVE_USER: &str = "user";
+    pub const OPT_GROUP: &str = "group";
+    pub const OPT_GROUPS: &str = "groups";
+    pub const OPT_HUMAN_READABLE: &str = "human-readable"; // GNU's id does not have this
+    pub const OPT_NAME: &str = "name";
+    pub const OPT_PASSWORD: &str = "password"; // GNU's id does not have this
+    pub const OPT_REAL_ID: &str = "real";
+    pub const OPT_ZERO: &str = "zero"; // BSD's id does not have this
+    pub const ARG_USERS: &str = "USER";
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [USER]...", uucore::execution_phrase())
+}
+
+fn get_description() -> String {
+    String::from(
+        "The id utility displays the user and group names and numeric IDs, of the \
+                      calling process, to the standard output. If the real and effective IDs are \
+                      different, both are displayed, otherwise only the real ID is displayed.\n\n\
+                      If a user (login name or user ID) is specified, the user and group IDs of \
+                      that user are displayed. In this case, the real and effective IDs are \
+                      assumed to be the same.",
+    )
+}
+
+struct Ids {
+    uid: u32,  // user id
+    gid: u32,  // group id
+    euid: u32, // effective uid
+    egid: u32, // effective gid
+}
+
+struct State {
+    nflag: bool,  // --name
+    uflag: bool,  // --user
+    gflag: bool,  // --group
+    gsflag: bool, // --groups
+    rflag: bool,  // --real
+    zflag: bool,  // --zero
+    cflag: bool,  // --context
+    selinux_supported: bool,
+    ids: Option<Ids>,
+    // The behavior for calling GNU's `id` and calling GNU's `id $USER` is similar but different.
+    // * The SELinux context is only displayed without a specified user.
+    // * The `getgroups` system call is only used without a specified user, this causes
+    //   the order of the displayed groups to be different between `id` and `id $USER`.
+    //
+    // Example:
+    // $ strace -e getgroups id -G $USER
+    // 1000 10 975 968
+    // +++ exited with 0 +++
+    // $ strace -e getgroups id -G
+    // getgroups(0, NULL)                      = 4
+    // getgroups(4, [10, 968, 975, 1000])      = 4
+    // 1000 10 968 975
+    // +++ exited with 0 +++
+    user_specified: bool,
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+    let after_help = get_description();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let users: Vec<String> = matches
+        .values_of(options::ARG_USERS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let mut state = State {
+        nflag: matches.is_present(options::OPT_NAME),
+        uflag: matches.is_present(options::OPT_EFFECTIVE_USER),
+        gflag: matches.is_present(options::OPT_GROUP),
+        gsflag: matches.is_present(options::OPT_GROUPS),
+        rflag: matches.is_present(options::OPT_REAL_ID),
+        zflag: matches.is_present(options::OPT_ZERO),
+        cflag: matches.is_present(options::OPT_CONTEXT),
+
+        selinux_supported: {
+            #[cfg(feature = "selinux")]
+            {
+                selinux::kernel_support() != selinux::KernelSupport::Unsupported
+            }
+            #[cfg(not(feature = "selinux"))]
+            {
+                false
+            }
+        },
+        user_specified: !users.is_empty(),
+        ids: None,
+    };
+
+    let default_format = {
+        // "default format" is when none of '-ugG' was used
+        !(state.uflag || state.gflag || state.gsflag)
+    };
+
+    if (state.nflag || state.rflag) && default_format && !state.cflag {
+        return Err(USimpleError::new(
+            1,
+            "cannot print only names or real IDs in default format",
+        ));
+    }
+    if state.zflag && default_format && !state.cflag {
+        // NOTE: GNU test suite "id/zero.sh" needs this stderr output:
+        return Err(USimpleError::new(
+            1,
+            "option --zero not permitted in default format",
+        ));
+    }
+    if state.user_specified && state.cflag {
+        return Err(USimpleError::new(
+            1,
+            "cannot print security context when user specified",
+        ));
+    }
+
+    let delimiter = {
+        if state.zflag {
+            "\0".to_string()
+        } else {
+            " ".to_string()
+        }
+    };
+    let line_ending = {
+        if state.zflag {
+            '\0'
+        } else {
+            '\n'
+        }
+    };
+
+    if state.cflag {
+        if state.selinux_supported {
+            // print SElinux context and exit
+            #[cfg(all(target_os = "linux", feature = "selinux"))]
+            if let Ok(context) = selinux::SecurityContext::current(false) {
+                let bytes = context.as_bytes();
+                print!("{}{}", String::from_utf8_lossy(bytes), line_ending);
+            } else {
+                // print error because `cflag` was explicitly requested
+                return Err(USimpleError::new(1, "can't get process context"));
+            }
+            return Ok(());
+        } else {
+            return Err(USimpleError::new(
+                1,
+                "--context (-Z) works only on an SELinux-enabled kernel",
+            ));
+        }
+    }
+
+    for i in 0..=users.len() {
+        let possible_pw = if !state.user_specified {
+            None
+        } else {
+            match Passwd::locate(users[i].as_str()) {
+                Ok(p) => Some(p),
+                Err(_) => {
+                    show_error!("'{}': no such user", users[i]);
+                    set_exit_code(1);
+                    if i + 1 >= users.len() {
+                        break;
+                    } else {
+                        continue;
+                    }
+                }
+            }
+        };
+
+        // GNU's `id` does not support the flags: -p/-P/-A.
+        if matches.is_present(options::OPT_PASSWORD) {
+            // BSD's `id` ignores all but the first specified user
+            pline(possible_pw.map(|v| v.uid()));
+            return Ok(());
+        };
+        if matches.is_present(options::OPT_HUMAN_READABLE) {
+            // BSD's `id` ignores all but the first specified user
+            pretty(possible_pw);
+            return Ok(());
+        }
+        if matches.is_present(options::OPT_AUDIT) {
+            // BSD's `id` ignores specified users
+            auditid();
+            return Ok(());
+        }
+
+        let (uid, gid) = possible_pw.map(|p| (p.uid(), p.gid())).unwrap_or((
+            if state.rflag { getuid() } else { geteuid() },
+            if state.rflag { getgid() } else { getegid() },
+        ));
+        state.ids = Some(Ids {
+            uid,
+            gid,
+            euid: geteuid(),
+            egid: getegid(),
+        });
+
+        if state.gflag {
+            print!(
+                "{}",
+                if state.nflag {
+                    entries::gid2grp(gid).unwrap_or_else(|_| {
+                        show_error!("cannot find name for group ID {}", gid);
+                        set_exit_code(1);
+                        gid.to_string()
+                    })
+                } else {
+                    gid.to_string()
+                }
+            );
+        }
+
+        if state.uflag {
+            print!(
+                "{}",
+                if state.nflag {
+                    entries::uid2usr(uid).unwrap_or_else(|_| {
+                        show_error!("cannot find name for user ID {}", uid);
+                        set_exit_code(1);
+                        uid.to_string()
+                    })
+                } else {
+                    uid.to_string()
+                }
+            );
+        }
+
+        let groups = entries::get_groups_gnu(Some(gid)).unwrap();
+        let groups = if state.user_specified {
+            possible_pw.map(|p| p.belongs_to()).unwrap()
+        } else {
+            groups.clone()
+        };
+
+        if state.gsflag {
+            print!(
+                "{}{}",
+                groups
+                    .iter()
+                    .map(|&id| {
+                        if state.nflag {
+                            entries::gid2grp(id).unwrap_or_else(|_| {
+                                show_error!("cannot find name for group ID {}", id);
+                                set_exit_code(1);
+                                id.to_string()
+                            })
+                        } else {
+                            id.to_string()
+                        }
+                    })
+                    .collect::<Vec<_>>()
+                    .join(&delimiter),
+                // NOTE: this is necessary to pass GNU's "tests/id/zero.sh":
+                if state.zflag && state.user_specified && users.len() > 1 {
+                    "\0"
+                } else {
+                    ""
+                }
+            );
+        }
+
+        if default_format {
+            id_print(&mut state, groups);
+        }
+        print!("{}", line_ending);
+
+        if i + 1 >= users.len() {
+            break;
+        }
+    }
+
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::OPT_AUDIT)
+                .short("A")
+                .conflicts_with_all(&[
+                    options::OPT_GROUP,
+                    options::OPT_EFFECTIVE_USER,
+                    options::OPT_HUMAN_READABLE,
+                    options::OPT_PASSWORD,
+                    options::OPT_GROUPS,
+                    options::OPT_ZERO,
+                ])
+                .help(
+                    "Display the process audit user ID and other process audit properties,\n\
+                      which requires privilege (not available on Linux).",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::OPT_EFFECTIVE_USER)
+                .short("u")
+                .long(options::OPT_EFFECTIVE_USER)
+                .conflicts_with(options::OPT_GROUP)
+                .help("Display only the effective user ID as a number."),
+        )
+        .arg(
+            Arg::with_name(options::OPT_GROUP)
+                .short("g")
+                .long(options::OPT_GROUP)
+                .conflicts_with(options::OPT_EFFECTIVE_USER)
+                .help("Display only the effective group ID as a number"),
+        )
+        .arg(
+            Arg::with_name(options::OPT_GROUPS)
+                .short("G")
+                .long(options::OPT_GROUPS)
+                .conflicts_with_all(&[
+                    options::OPT_GROUP,
+                    options::OPT_EFFECTIVE_USER,
+                    options::OPT_CONTEXT,
+                    options::OPT_HUMAN_READABLE,
+                    options::OPT_PASSWORD,
+                    options::OPT_AUDIT,
+                ])
+                .help(
+                    "Display only the different group IDs as white-space separated numbers, \
+                      in no particular order.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::OPT_HUMAN_READABLE)
+                .short("p")
+                .help("Make the output human-readable. Each display is on a separate line."),
+        )
+        .arg(
+            Arg::with_name(options::OPT_NAME)
+                .short("n")
+                .long(options::OPT_NAME)
+                .help(
+                    "Display the name of the user or group ID for the -G, -g and -u options \
+                      instead of the number.\nIf any of the ID numbers cannot be mapped into \
+                      names, the number will be displayed as usual.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::OPT_PASSWORD)
+                .short("P")
+                .help("Display the id as a password file entry."),
+        )
+        .arg(
+            Arg::with_name(options::OPT_REAL_ID)
+                .short("r")
+                .long(options::OPT_REAL_ID)
+                .help(
+                    "Display the real ID for the -G, -g and -u options instead of \
+                      the effective ID.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::OPT_ZERO)
+                .short("z")
+                .long(options::OPT_ZERO)
+                .help(
+                    "delimit entries with NUL characters, not whitespace;\n\
+                      not permitted in default format",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::OPT_CONTEXT)
+                .short("Z")
+                .long(options::OPT_CONTEXT)
+                .conflicts_with_all(&[options::OPT_GROUP, options::OPT_EFFECTIVE_USER])
+                .help(CONTEXT_HELP_TEXT),
+        )
+        .arg(
+            Arg::with_name(options::ARG_USERS)
+                .multiple(true)
+                .takes_value(true)
+                .value_name(options::ARG_USERS),
+        )
+}
+
+fn pretty(possible_pw: Option<Passwd>) {
+    if let Some(p) = possible_pw {
+        print!("uid\t{}\ngroups\t", p.name());
+        println!(
+            "{}",
+            p.belongs_to()
+                .iter()
+                .map(|&gr| entries::gid2grp(gr).unwrap())
+                .collect::<Vec<_>>()
+                .join(" ")
+        );
+    } else {
+        let login = cstr2cow!(getlogin() as *const _);
+        let rid = getuid();
+        if let Ok(p) = Passwd::locate(rid) {
+            if login == p.name() {
+                println!("login\t{}", login);
+            }
+            println!("uid\t{}", p.name());
+        } else {
+            println!("uid\t{}", rid);
+        }
+
+        let eid = getegid();
+        if eid == rid {
+            if let Ok(p) = Passwd::locate(eid) {
+                println!("euid\t{}", p.name());
+            } else {
+                println!("euid\t{}", eid);
+            }
+        }
+
+        let rid = getgid();
+        if rid != eid {
+            if let Ok(g) = Group::locate(rid) {
+                println!("euid\t{}", g.name());
+            } else {
+                println!("euid\t{}", rid);
+            }
+        }
+
+        println!(
+            "groups\t{}",
+            entries::get_groups_gnu(None)
+                .unwrap()
+                .iter()
+                .map(|&gr| entries::gid2grp(gr).unwrap())
+                .collect::<Vec<_>>()
+                .join(" ")
+        );
+    }
+}
+
+#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
+fn pline(possible_uid: Option<uid_t>) {
+    let uid = possible_uid.unwrap_or_else(getuid);
+    let pw = Passwd::locate(uid).unwrap();
+
+    println!(
+        "{}:{}:{}:{}:{}:{}:{}:{}:{}:{}",
+        pw.name(),
+        pw.user_passwd(),
+        pw.uid(),
+        pw.gid(),
+        pw.user_access_class(),
+        pw.passwd_change_time(),
+        pw.expiration(),
+        pw.user_info(),
+        pw.user_dir(),
+        pw.user_shell()
+    );
+}
+
+#[cfg(target_os = "linux")]
+fn pline(possible_uid: Option<uid_t>) {
+    let uid = possible_uid.unwrap_or_else(getuid);
+    let pw = Passwd::locate(uid).unwrap();
+
+    println!(
+        "{}:{}:{}:{}:{}:{}:{}",
+        pw.name(),
+        pw.user_passwd(),
+        pw.uid(),
+        pw.gid(),
+        pw.user_info(),
+        pw.user_dir(),
+        pw.user_shell()
+    );
+}
+
+#[cfg(target_os = "linux")]
+fn auditid() {}
+
+#[cfg(not(target_os = "linux"))]
+fn auditid() {
+    #[allow(deprecated)]
+    let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { std::mem::uninitialized() };
+    let address = &mut auditinfo as *mut audit::c_auditinfo_addr_t;
+    if unsafe { audit::getaudit(address) } < 0 {
+        println!("couldn't retrieve information");
+        return;
+    }
+
+    println!("auid={}", auditinfo.ai_auid);
+    println!("mask.success=0x{:x}", auditinfo.ai_mask.am_success);
+    println!("mask.failure=0x{:x}", auditinfo.ai_mask.am_failure);
+    println!("termid.port=0x{:x}", auditinfo.ai_termid.port);
+    println!("asid={}", auditinfo.ai_asid);
+}
+
+fn id_print(state: &mut State, groups: Vec<u32>) {
+    let uid = state.ids.as_ref().unwrap().uid;
+    let gid = state.ids.as_ref().unwrap().gid;
+    let euid = state.ids.as_ref().unwrap().euid;
+    let egid = state.ids.as_ref().unwrap().egid;
+
+    print!(
+        "uid={}({})",
+        uid,
+        entries::uid2usr(uid).unwrap_or_else(|_| {
+            show_error!("cannot find name for user ID {}", uid);
+            set_exit_code(1);
+            uid.to_string()
+        })
+    );
+    print!(
+        " gid={}({})",
+        gid,
+        entries::gid2grp(gid).unwrap_or_else(|_| {
+            show_error!("cannot find name for group ID {}", gid);
+            set_exit_code(1);
+            gid.to_string()
+        })
+    );
+    if !state.user_specified && (euid != uid) {
+        print!(
+            " euid={}({})",
+            euid,
+            entries::uid2usr(euid).unwrap_or_else(|_| {
+                show_error!("cannot find name for user ID {}", euid);
+                set_exit_code(1);
+                euid.to_string()
+            })
+        );
+    }
+    if !state.user_specified && (egid != gid) {
+        print!(
+            " egid={}({})",
+            euid,
+            entries::gid2grp(egid).unwrap_or_else(|_| {
+                show_error!("cannot find name for group ID {}", egid);
+                set_exit_code(1);
+                egid.to_string()
+            })
+        );
+    }
+    print!(
+        " groups={}",
+        groups
+            .iter()
+            .map(|&gr| format!(
+                "{}({})",
+                gr,
+                entries::gid2grp(gr).unwrap_or_else(|_| {
+                    show_error!("cannot find name for group ID {}", gr);
+                    set_exit_code(1);
+                    gr.to_string()
+                })
+            ))
+            .collect::<Vec<_>>()
+            .join(",")
+    );
+
+    #[cfg(all(target_os = "linux", feature = "selinux"))]
+    if state.selinux_supported
+        && !state.user_specified
+        && std::env::var_os("POSIXLY_CORRECT").is_none()
+    {
+        // print SElinux context (does not depend on "-Z")
+        if let Ok(context) = selinux::SecurityContext::current(false) {
+            let bytes = context.as_bytes();
+            print!(" context={}", String::from_utf8_lossy(bytes));
+        }
+    }
+}
+
+#[cfg(not(target_os = "linux"))]
+mod audit {
+    use super::libc::{c_int, c_uint, dev_t, pid_t, uid_t};
+
+    pub type au_id_t = uid_t;
+    pub type au_asid_t = pid_t;
+    pub type au_event_t = c_uint;
+    pub type au_emod_t = c_uint;
+    pub type au_class_t = c_int;
+    pub type au_flag_t = u64;
+
+    #[repr(C)]
+    pub struct au_mask {
+        pub am_success: c_uint,
+        pub am_failure: c_uint,
+    }
+    pub type au_mask_t = au_mask;
+
+    #[repr(C)]
+    pub struct au_tid_addr {
+        pub port: dev_t,
+    }
+    pub type au_tid_addr_t = au_tid_addr;
+
+    #[repr(C)]
+    pub struct c_auditinfo_addr {
+        pub ai_auid: au_id_t,         // Audit user ID
+        pub ai_mask: au_mask_t,       // Audit masks.
+        pub ai_termid: au_tid_addr_t, // Terminal ID.
+        pub ai_asid: au_asid_t,       // Audit session ID.
+        pub ai_flags: au_flag_t,      // Audit session flags
+    }
+    pub type c_auditinfo_addr_t = c_auditinfo_addr;
+
+    extern "C" {
+        pub fn getaudit(auditinfo_addr: *mut c_auditinfo_addr_t) -> c_int;
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_install/install.rs.html b/src/uu_install/install.rs.html new file mode 100644 index 000000000..4850115fb --- /dev/null +++ b/src/uu_install/install.rs.html @@ -0,0 +1,1587 @@ +install.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Ben Eills <ben@beneills.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE file
+//  * that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) rwxr sourcepath targetpath Isnt uioerror
+
+mod mode;
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use file_diff::diff;
+use filetime::{set_file_times, FileTime};
+use uucore::backup_control::{self, BackupMode};
+use uucore::entries::{grp2gid, usr2uid};
+use uucore::error::{FromIo, UError, UIoError, UResult, USimpleError};
+use uucore::perms::{wrap_chown, Verbosity, VerbosityLevel};
+
+use libc::{getegid, geteuid};
+use std::error::Error;
+use std::fmt::{Debug, Display};
+use std::fs;
+use std::fs::File;
+use std::os::unix::fs::MetadataExt;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+const DEFAULT_MODE: u32 = 0o755;
+const DEFAULT_STRIP_PROGRAM: &str = "strip";
+
+#[allow(dead_code)]
+pub struct Behavior {
+    main_function: MainFunction,
+    specified_mode: Option<u32>,
+    backup_mode: BackupMode,
+    suffix: String,
+    owner: String,
+    group: String,
+    verbose: bool,
+    preserve_timestamps: bool,
+    compare: bool,
+    strip: bool,
+    strip_program: String,
+    create_leading: bool,
+    target_dir: Option<String>,
+}
+
+#[derive(Debug)]
+enum InstallError {
+    Unimplemented(String),
+    DirNeedsArg(),
+    CreateDirFailed(PathBuf, std::io::Error),
+    ChmodFailed(PathBuf),
+    InvalidTarget(PathBuf),
+    TargetDirIsntDir(PathBuf),
+    BackupFailed(PathBuf, PathBuf, std::io::Error),
+    InstallFailed(PathBuf, PathBuf, std::io::Error),
+    StripProgramFailed(String),
+    MetadataFailed(std::io::Error),
+    NoSuchUser(String),
+    NoSuchGroup(String),
+    OmittingDirectory(PathBuf),
+}
+
+impl UError for InstallError {
+    fn code(&self) -> i32 {
+        match self {
+            InstallError::Unimplemented(_) => 2,
+            _ => 1,
+        }
+    }
+
+    fn usage(&self) -> bool {
+        false
+    }
+}
+
+impl Error for InstallError {}
+
+impl Display for InstallError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use InstallError as IE;
+        match self {
+            IE::Unimplemented(opt) => write!(f, "Unimplemented feature: {}", opt),
+            IE::DirNeedsArg() => {
+                write!(
+                    f,
+                    "{} with -d requires at least one argument.",
+                    uucore::util_name()
+                )
+            }
+            IE::CreateDirFailed(dir, e) => {
+                Display::fmt(&uio_error!(e, "failed to create {}", dir.display()), f)
+            }
+            IE::ChmodFailed(file) => write!(f, "failed to chmod {}", file.display()),
+            IE::InvalidTarget(target) => write!(
+                f,
+                "invalid target {}: No such file or directory",
+                target.display()
+            ),
+            IE::TargetDirIsntDir(target) => {
+                write!(f, "target '{}' is not a directory", target.display())
+            }
+            IE::BackupFailed(from, to, e) => Display::fmt(
+                &uio_error!(
+                    e,
+                    "cannot backup '{}' to '{}'",
+                    from.display(),
+                    to.display()
+                ),
+                f,
+            ),
+            IE::InstallFailed(from, to, e) => Display::fmt(
+                &uio_error!(
+                    e,
+                    "cannot install '{}' to '{}'",
+                    from.display(),
+                    to.display()
+                ),
+                f,
+            ),
+            IE::StripProgramFailed(msg) => write!(f, "strip program failed: {}", msg),
+            IE::MetadataFailed(e) => Display::fmt(&uio_error!(e, ""), f),
+            IE::NoSuchUser(user) => write!(f, "no such user: {}", user),
+            IE::NoSuchGroup(group) => write!(f, "no such group: {}", group),
+            IE::OmittingDirectory(dir) => write!(f, "omitting directory '{}'", dir.display()),
+        }
+    }
+}
+
+#[derive(Clone, Eq, PartialEq)]
+pub enum MainFunction {
+    /// Create directories
+    Directory,
+    /// Install files to locations (primary functionality)
+    Standard,
+}
+
+impl Behavior {
+    /// Determine the mode for chmod after copy.
+    pub fn mode(&self) -> u32 {
+        match self.specified_mode {
+            Some(x) => x,
+            None => DEFAULT_MODE,
+        }
+    }
+}
+
+static ABOUT: &str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
+ DIRECTORY, while setting permission modes and owner/group";
+
+static OPT_COMPARE: &str = "compare";
+static OPT_BACKUP: &str = "backup";
+static OPT_BACKUP_NO_ARG: &str = "backup2";
+static OPT_DIRECTORY: &str = "directory";
+static OPT_IGNORED: &str = "ignored";
+static OPT_CREATE_LEADING: &str = "create-leading";
+static OPT_GROUP: &str = "group";
+static OPT_MODE: &str = "mode";
+static OPT_OWNER: &str = "owner";
+static OPT_PRESERVE_TIMESTAMPS: &str = "preserve-timestamps";
+static OPT_STRIP: &str = "strip";
+static OPT_STRIP_PROGRAM: &str = "strip-program";
+static OPT_SUFFIX: &str = "suffix";
+static OPT_TARGET_DIRECTORY: &str = "target-directory";
+static OPT_NO_TARGET_DIRECTORY: &str = "no-target-directory";
+static OPT_VERBOSE: &str = "verbose";
+static OPT_PRESERVE_CONTEXT: &str = "preserve-context";
+static OPT_CONTEXT: &str = "context";
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+/// Main install utility function, called from main.rs.
+///
+/// Returns a program return code.
+///
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let paths: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    check_unimplemented(&matches)?;
+
+    let behavior = behavior(&matches)?;
+
+    match behavior.main_function {
+        MainFunction::Directory => directory(paths, behavior),
+        MainFunction::Standard => standard(paths, behavior),
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+                Arg::with_name(OPT_BACKUP)
+                .long(OPT_BACKUP)
+                .help("make a backup of each existing destination file")
+                .takes_value(true)
+                .require_equals(true)
+                .min_values(0)
+                .value_name("CONTROL")
+        )
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_BACKUP_NO_ARG)
+            .short("b")
+            .help("like --backup but does not accept an argument")
+        )
+        .arg(
+            Arg::with_name(OPT_IGNORED)
+            .short("c")
+            .help("ignored")
+        )
+        .arg(
+            Arg::with_name(OPT_COMPARE)
+            .short("C")
+            .long(OPT_COMPARE)
+            .help("compare each pair of source and destination files, and in some cases, do not modify the destination at all")
+        )
+        .arg(
+            Arg::with_name(OPT_DIRECTORY)
+                .short("d")
+                .long(OPT_DIRECTORY)
+                .help("treat all arguments as directory names. create all components of the specified directories")
+        )
+
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_CREATE_LEADING)
+                .short("D")
+                .help("create all leading components of DEST except the last, then copy SOURCE to DEST")
+        )
+        .arg(
+            Arg::with_name(OPT_GROUP)
+                .short("g")
+                .long(OPT_GROUP)
+                .help("set group ownership, instead of process's current group")
+                .value_name("GROUP")
+                .takes_value(true)
+        )
+        .arg(
+            Arg::with_name(OPT_MODE)
+                .short("m")
+                .long(OPT_MODE)
+                .help("set permission mode (as in chmod), instead of rwxr-xr-x")
+                .value_name("MODE")
+                .takes_value(true)
+        )
+        .arg(
+            Arg::with_name(OPT_OWNER)
+                .short("o")
+                .long(OPT_OWNER)
+                .help("set ownership (super-user only)")
+                .value_name("OWNER")
+                .takes_value(true)
+        )
+        .arg(
+            Arg::with_name(OPT_PRESERVE_TIMESTAMPS)
+                .short("p")
+                .long(OPT_PRESERVE_TIMESTAMPS)
+                .help("apply access/modification times of SOURCE files to corresponding destination files")
+        )
+        .arg(
+            Arg::with_name(OPT_STRIP)
+            .short("s")
+            .long(OPT_STRIP)
+            .help("strip symbol tables (no action Windows)")
+        )
+        .arg(
+            Arg::with_name(OPT_STRIP_PROGRAM)
+                .long(OPT_STRIP_PROGRAM)
+                .help("program used to strip binaries (no action Windows)")
+                .value_name("PROGRAM")
+        )
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_SUFFIX)
+                .short("S")
+                .long(OPT_SUFFIX)
+                .help("override the usual backup suffix")
+                .value_name("SUFFIX")
+                .takes_value(true)
+                .min_values(1)
+        )
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_TARGET_DIRECTORY)
+                .short("t")
+                .long(OPT_TARGET_DIRECTORY)
+                .help("move all SOURCE arguments into DIRECTORY")
+                .value_name("DIRECTORY")
+        )
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_NO_TARGET_DIRECTORY)
+                .short("T")
+                .long(OPT_NO_TARGET_DIRECTORY)
+                .help("(unimplemented) treat DEST as a normal file")
+
+        )
+        .arg(
+            Arg::with_name(OPT_VERBOSE)
+            .short("v")
+            .long(OPT_VERBOSE)
+            .help("explain what is being done")
+        )
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_PRESERVE_CONTEXT)
+                .short("P")
+                .long(OPT_PRESERVE_CONTEXT)
+                .help("(unimplemented) preserve security context")
+        )
+        .arg(
+            // TODO implement flag
+            Arg::with_name(OPT_CONTEXT)
+                .short("Z")
+                .long(OPT_CONTEXT)
+                .help("(unimplemented) set security context of files and directories")
+                .value_name("CONTEXT")
+        )
+        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true).min_values(1))
+}
+
+/// Check for unimplemented command line arguments.
+///
+/// Either return the degenerate Ok value, or an Err with string.
+///
+/// # Errors
+///
+/// Error datum is a string of the unimplemented argument.
+///
+///
+fn check_unimplemented(matches: &ArgMatches) -> UResult<()> {
+    if matches.is_present(OPT_NO_TARGET_DIRECTORY) {
+        Err(InstallError::Unimplemented(String::from("--no-target-directory, -T")).into())
+    } else if matches.is_present(OPT_PRESERVE_CONTEXT) {
+        Err(InstallError::Unimplemented(String::from("--preserve-context, -P")).into())
+    } else if matches.is_present(OPT_CONTEXT) {
+        Err(InstallError::Unimplemented(String::from("--context, -Z")).into())
+    } else {
+        Ok(())
+    }
+}
+
+/// Determine behavior, given command line arguments.
+///
+/// If successful, returns a filled-out Behavior struct.
+///
+/// # Errors
+///
+/// In event of failure, returns an integer intended as a program return code.
+///
+fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
+    let main_function = if matches.is_present(OPT_DIRECTORY) {
+        MainFunction::Directory
+    } else {
+        MainFunction::Standard
+    };
+
+    let considering_dir: bool = MainFunction::Directory == main_function;
+
+    let specified_mode: Option<u32> = if matches.is_present(OPT_MODE) {
+        let x = matches.value_of(OPT_MODE).ok_or(1)?;
+        Some(mode::parse(x, considering_dir).map_err(|err| {
+            show_error!("Invalid mode string: {}", err);
+            1
+        })?)
+    } else {
+        None
+    };
+
+    let backup_mode = backup_control::determine_backup_mode(
+        matches.is_present(OPT_BACKUP_NO_ARG),
+        matches.is_present(OPT_BACKUP),
+        matches.value_of(OPT_BACKUP),
+    );
+    let backup_mode = match backup_mode {
+        Err(err) => return Err(USimpleError::new(1, err)),
+        Ok(mode) => mode,
+    };
+
+    let target_dir = matches.value_of(OPT_TARGET_DIRECTORY).map(|d| d.to_owned());
+
+    Ok(Behavior {
+        main_function,
+        specified_mode,
+        backup_mode,
+        suffix: backup_control::determine_backup_suffix(matches.value_of(OPT_SUFFIX)),
+        owner: matches.value_of(OPT_OWNER).unwrap_or("").to_string(),
+        group: matches.value_of(OPT_GROUP).unwrap_or("").to_string(),
+        verbose: matches.is_present(OPT_VERBOSE),
+        preserve_timestamps: matches.is_present(OPT_PRESERVE_TIMESTAMPS),
+        compare: matches.is_present(OPT_COMPARE),
+        strip: matches.is_present(OPT_STRIP),
+        strip_program: String::from(
+            matches
+                .value_of(OPT_STRIP_PROGRAM)
+                .unwrap_or(DEFAULT_STRIP_PROGRAM),
+        ),
+        create_leading: matches.is_present(OPT_CREATE_LEADING),
+        target_dir,
+    })
+}
+
+/// Creates directories.
+///
+/// GNU man pages describe this functionality as creating 'all components of
+/// the specified directories'.
+///
+/// Returns a Result type with the Err variant containing the error message.
+///
+fn directory(paths: Vec<String>, b: Behavior) -> UResult<()> {
+    if paths.is_empty() {
+        Err(InstallError::DirNeedsArg().into())
+    } else {
+        for path in paths.iter().map(Path::new) {
+            // if the path already exist, don't try to create it again
+            if !path.exists() {
+                // Differently than the primary functionality
+                // (MainFunction::Standard), the directory functionality should
+                // create all ancestors (or components) of a directory
+                // regardless of the presence of the "-D" flag.
+                //
+                // NOTE: the GNU "install" sets the expected mode only for the
+                // target directory. All created ancestor directories will have
+                // the default mode. Hence it is safe to use fs::create_dir_all
+                // and then only modify the target's dir mode.
+                if let Err(e) =
+                    fs::create_dir_all(path).map_err_context(|| format!("{}", path.display()))
+                {
+                    show!(e);
+                    continue;
+                }
+
+                if b.verbose {
+                    println!("creating directory '{}'", path.display());
+                }
+            }
+
+            if mode::chmod(path, b.mode()).is_err() {
+                // Error messages are printed by the mode::chmod function!
+                uucore::error::set_exit_code(1);
+                continue;
+            }
+        }
+        // If the exit code was set, or show! has been called at least once
+        // (which sets the exit code as well), function execution will end after
+        // this return.
+        Ok(())
+    }
+}
+
+/// Test if the path is a new file path that can be
+/// created immediately
+fn is_new_file_path(path: &Path) -> bool {
+    !path.exists()
+        && (path.parent().map(Path::is_dir).unwrap_or(true)
+            || path.parent().unwrap().to_string_lossy().is_empty()) // In case of a simple file
+}
+
+/// Perform an install, given a list of paths and behavior.
+///
+/// Returns a Result type with the Err variant containing the error message.
+///
+fn standard(mut paths: Vec<String>, b: Behavior) -> UResult<()> {
+    let target: PathBuf = b
+        .target_dir
+        .clone()
+        .unwrap_or_else(|| paths.pop().unwrap())
+        .into();
+
+    let sources = &paths.iter().map(PathBuf::from).collect::<Vec<_>>();
+
+    if sources.len() > 1 || (target.exists() && target.is_dir()) {
+        copy_files_into_dir(sources, &target, &b)
+    } else {
+        if let Some(parent) = target.parent() {
+            if !parent.exists() && b.create_leading {
+                if let Err(e) = fs::create_dir_all(parent) {
+                    return Err(InstallError::CreateDirFailed(parent.to_path_buf(), e).into());
+                }
+
+                if mode::chmod(parent, b.mode()).is_err() {
+                    return Err(InstallError::ChmodFailed(parent.to_path_buf()).into());
+                }
+            }
+        }
+
+        if target.is_file() || is_new_file_path(&target) {
+            copy(&sources[0], &target, &b)
+        } else {
+            Err(InstallError::InvalidTarget(target).into())
+        }
+    }
+}
+
+/// Copy some files into a directory.
+///
+/// Prints verbose information and error messages.
+/// Returns a Result type with the Err variant containing the error message.
+///
+/// # Parameters
+///
+/// _files_ must all exist as non-directories.
+/// _target_dir_ must be a directory.
+///
+fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UResult<()> {
+    if !target_dir.is_dir() {
+        return Err(InstallError::TargetDirIsntDir(target_dir.to_path_buf()).into());
+    }
+    for sourcepath in files.iter() {
+        if !sourcepath.exists() {
+            let err = UIoError::new(
+                std::io::ErrorKind::NotFound,
+                format!("cannot stat '{}'", sourcepath.display()),
+            );
+            show!(err);
+            continue;
+        }
+
+        if sourcepath.is_dir() {
+            let err = InstallError::OmittingDirectory(sourcepath.to_path_buf());
+            show!(err);
+            continue;
+        }
+
+        let mut targetpath = target_dir.to_path_buf();
+        let filename = sourcepath.components().last().unwrap();
+        targetpath.push(filename);
+
+        show_if_err!(copy(sourcepath, &targetpath, b));
+    }
+    // If the exit code was set, or show! has been called at least once
+    // (which sets the exit code as well), function execution will end after
+    // this return.
+    Ok(())
+}
+
+/// Copy one file to a new location, changing metadata.
+///
+/// Returns a Result type with the Err variant containing the error message.
+///
+/// # Parameters
+///
+/// _from_ must exist as a non-directory.
+/// _to_ must be a non-existent file, whose parent directory exists.
+///
+/// # Errors
+///
+/// If the copy system call fails, we print a verbose error and return an empty error value.
+///
+#[allow(clippy::cognitive_complexity)]
+fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
+    if b.compare && !need_copy(from, to, b)? {
+        return Ok(());
+    }
+    // Declare the path here as we may need it for the verbose output below.
+    let mut backup_path = None;
+
+    // Perform backup, if any, before overwriting 'to'
+    //
+    // The codes actually making use of the backup process don't seem to agree
+    // on how best to approach the issue. (mv and ln, for example)
+    if to.exists() {
+        backup_path = backup_control::get_backup_path(b.backup_mode, to, &b.suffix);
+        if let Some(ref backup_path) = backup_path {
+            // TODO!!
+            if let Err(err) = fs::rename(to, backup_path) {
+                return Err(InstallError::BackupFailed(
+                    to.to_path_buf(),
+                    backup_path.to_path_buf(),
+                    err,
+                )
+                .into());
+            }
+        }
+    }
+
+    if from.to_string_lossy() == "/dev/null" {
+        /* workaround a limitation of fs::copy
+         * https://github.com/rust-lang/rust/issues/79390
+         */
+        if let Err(err) = File::create(to) {
+            return Err(
+                InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into(),
+            );
+        }
+    } else if let Err(err) = fs::copy(from, to) {
+        return Err(InstallError::InstallFailed(from.to_path_buf(), to.to_path_buf(), err).into());
+    }
+
+    if b.strip && cfg!(not(windows)) {
+        match Command::new(&b.strip_program).arg(to).output() {
+            Ok(o) => {
+                if !o.status.success() {
+                    return Err(InstallError::StripProgramFailed(
+                        String::from_utf8(o.stderr).unwrap_or_default(),
+                    )
+                    .into());
+                }
+            }
+            Err(e) => return Err(InstallError::StripProgramFailed(e.to_string()).into()),
+        }
+    }
+
+    if mode::chmod(to, b.mode()).is_err() {
+        return Err(InstallError::ChmodFailed(to.to_path_buf()).into());
+    }
+
+    if !b.owner.is_empty() {
+        let meta = match fs::metadata(to) {
+            Ok(meta) => meta,
+            Err(e) => return Err(InstallError::MetadataFailed(e).into()),
+        };
+
+        let owner_id = match usr2uid(&b.owner) {
+            Ok(g) => g,
+            _ => return Err(InstallError::NoSuchUser(b.owner.clone()).into()),
+        };
+        let gid = meta.gid();
+        match wrap_chown(
+            to,
+            &meta,
+            Some(owner_id),
+            Some(gid),
+            false,
+            Verbosity {
+                groups_only: false,
+                level: VerbosityLevel::Normal,
+            },
+        ) {
+            Ok(n) => {
+                if !n.is_empty() {
+                    show_error!("{}", n);
+                }
+            }
+            Err(e) => show_error!("{}", e),
+        }
+    }
+
+    if !b.group.is_empty() {
+        let meta = match fs::metadata(to) {
+            Ok(meta) => meta,
+            Err(e) => return Err(InstallError::MetadataFailed(e).into()),
+        };
+
+        let group_id = match grp2gid(&b.group) {
+            Ok(g) => g,
+            _ => return Err(InstallError::NoSuchGroup(b.group.clone()).into()),
+        };
+        match wrap_chown(
+            to,
+            &meta,
+            Some(group_id),
+            None,
+            false,
+            Verbosity {
+                groups_only: true,
+                level: VerbosityLevel::Normal,
+            },
+        ) {
+            Ok(n) => {
+                if !n.is_empty() {
+                    show_error!("{}", n);
+                }
+            }
+            Err(e) => show_error!("{}", e),
+        }
+    }
+
+    if b.preserve_timestamps {
+        let meta = match fs::metadata(from) {
+            Ok(meta) => meta,
+            Err(e) => return Err(InstallError::MetadataFailed(e).into()),
+        };
+
+        let modified_time = FileTime::from_last_modification_time(&meta);
+        let accessed_time = FileTime::from_last_access_time(&meta);
+
+        match set_file_times(to, accessed_time, modified_time) {
+            Ok(_) => {}
+            Err(e) => show_error!("{}", e),
+        }
+    }
+
+    if b.verbose {
+        print!("'{}' -> '{}'", from.display(), to.display());
+        match backup_path {
+            Some(path) => println!(" (backup: '{}')", path.display()),
+            None => println!(),
+        }
+    }
+
+    Ok(())
+}
+
+/// Return true if a file is necessary to copy. This is the case when:
+///
+/// - _from_ or _to_ is nonexistent;
+/// - either file has a sticky bit or set[ug]id bit, or the user specified one;
+/// - either file isn't a regular file;
+/// - the sizes of _from_ and _to_ differ;
+/// - _to_'s owner differs from intended; or
+/// - the contents of _from_ and _to_ differ.
+///
+/// # Parameters
+///
+/// _from_ and _to_, if existent, must be non-directories.
+///
+/// # Errors
+///
+/// Crashes the program if a nonexistent owner or group is specified in _b_.
+///
+fn need_copy(from: &Path, to: &Path, b: &Behavior) -> UResult<bool> {
+    let from_meta = match fs::metadata(from) {
+        Ok(meta) => meta,
+        Err(_) => return Ok(true),
+    };
+    let to_meta = match fs::metadata(to) {
+        Ok(meta) => meta,
+        Err(_) => return Ok(true),
+    };
+
+    // setuid || setgid || sticky
+    let extra_mode: u32 = 0o7000;
+
+    if b.specified_mode.unwrap_or(0) & extra_mode != 0
+        || from_meta.mode() & extra_mode != 0
+        || to_meta.mode() & extra_mode != 0
+    {
+        return Ok(true);
+    }
+
+    if !from_meta.is_file() || !to_meta.is_file() {
+        return Ok(true);
+    }
+
+    if from_meta.len() != to_meta.len() {
+        return Ok(true);
+    }
+
+    // TODO: if -P (#1809) and from/to contexts mismatch, return true.
+
+    if !b.owner.is_empty() {
+        let owner_id = match usr2uid(&b.owner) {
+            Ok(id) => id,
+            _ => return Err(InstallError::NoSuchUser(b.owner.clone()).into()),
+        };
+        if owner_id != to_meta.uid() {
+            return Ok(true);
+        }
+    } else if !b.group.is_empty() {
+        let group_id = match grp2gid(&b.group) {
+            Ok(id) => id,
+            _ => return Err(InstallError::NoSuchGroup(b.group.clone()).into()),
+        };
+        if group_id != to_meta.gid() {
+            return Ok(true);
+        }
+    } else {
+        #[cfg(not(target_os = "windows"))]
+        unsafe {
+            if to_meta.uid() != geteuid() || to_meta.gid() != getegid() {
+                return Ok(true);
+            }
+        }
+    }
+
+    if !diff(from.to_str().unwrap(), to.to_str().unwrap()) {
+        return Ok(true);
+    }
+
+    Ok(false)
+}
+
+
\ No newline at end of file diff --git a/src/uu_install/mode.rs.html b/src/uu_install/mode.rs.html new file mode 100644 index 000000000..a6dec05ac --- /dev/null +++ b/src/uu_install/mode.rs.html @@ -0,0 +1,81 @@ +mode.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+
+use std::fs;
+use std::path::Path;
+#[cfg(not(windows))]
+use uucore::mode;
+
+/// Takes a user-supplied string and tries to parse to u16 mode bitmask.
+pub fn parse(mode_string: &str, considering_dir: bool) -> Result<u32, String> {
+    let numbers: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+
+    // Passing 000 as the existing permissions seems to mirror GNU behavior.
+    if mode_string.contains(numbers) {
+        mode::parse_numeric(0, mode_string)
+    } else {
+        mode::parse_symbolic(0, mode_string, considering_dir)
+    }
+}
+
+/// chmod a file or directory on UNIX.
+///
+/// Adapted from mkdir.rs.  Handles own error printing.
+///
+#[cfg(any(unix, target_os = "redox"))]
+pub fn chmod(path: &Path, mode: u32) -> Result<(), ()> {
+    use std::os::unix::fs::PermissionsExt;
+    fs::set_permissions(path, fs::Permissions::from_mode(mode)).map_err(|err| {
+        show_error!("{}: chmod failed with error {}", path.display(), err);
+    })
+}
+
+/// chmod a file or directory on Windows.
+///
+/// Adapted from mkdir.rs.
+///
+#[cfg(windows)]
+pub fn chmod(path: &Path, mode: u32) -> Result<(), ()> {
+    // chmod on Windows only sets the readonly flag, which isn't even honored on directories
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_join/join.rs.html b/src/uu_join/join.rs.html new file mode 100644 index 000000000..e2533f3f1 --- /dev/null +++ b/src/uu_join/join.rs.html @@ -0,0 +1,1473 @@ +join.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Konstantin Pospelov <kupospelov@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) autoformat FILENUM whitespaces pairable unpairable nocheck
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::cmp::{min, Ordering};
+use std::fs::File;
+use std::io::{stdin, BufRead, BufReader, Lines, Stdin};
+
+static NAME: &str = "join";
+
+#[derive(Copy, Clone, PartialEq)]
+enum FileNum {
+    File1,
+    File2,
+}
+
+#[derive(Copy, Clone)]
+enum Sep {
+    Char(char),
+    Line,
+    Whitespaces,
+}
+
+#[derive(Copy, Clone, PartialEq)]
+enum CheckOrder {
+    Default,
+    Disabled,
+    Enabled,
+}
+
+struct Settings {
+    key1: usize,
+    key2: usize,
+    print_unpaired1: bool,
+    print_unpaired2: bool,
+    print_joined: bool,
+    ignore_case: bool,
+    separator: Sep,
+    autoformat: bool,
+    format: Vec<Spec>,
+    empty: String,
+    check_order: CheckOrder,
+    headers: bool,
+}
+
+impl Default for Settings {
+    fn default() -> Settings {
+        Settings {
+            key1: 0,
+            key2: 0,
+            print_unpaired1: false,
+            print_unpaired2: false,
+            print_joined: true,
+            ignore_case: false,
+            separator: Sep::Whitespaces,
+            autoformat: false,
+            format: vec![],
+            empty: String::new(),
+            check_order: CheckOrder::Default,
+            headers: false,
+        }
+    }
+}
+
+/// Output representation.
+struct Repr<'a> {
+    separator: char,
+    format: &'a [Spec],
+    empty: &'a str,
+}
+
+impl<'a> Repr<'a> {
+    fn new(separator: char, format: &'a [Spec], empty: &'a str) -> Repr<'a> {
+        Repr {
+            separator,
+            format,
+            empty,
+        }
+    }
+
+    fn uses_format(&self) -> bool {
+        !self.format.is_empty()
+    }
+
+    /// Print the field or empty filler if the field is not set.
+    fn print_field(&self, field: Option<&str>) {
+        let value = match field {
+            Some(field) => field,
+            None => self.empty,
+        };
+
+        print!("{}", value);
+    }
+
+    /// Print each field except the one at the index.
+    fn print_fields(&self, line: &Line, index: usize, max_fields: Option<usize>) {
+        for i in 0..min(max_fields.unwrap_or(usize::max_value()), line.fields.len()) {
+            if i != index {
+                print!("{}{}", self.separator, line.fields[i]);
+            }
+        }
+        if let Some(n) = max_fields {
+            for _ in line.fields.len()..n {
+                print!("{}", self.separator)
+            }
+        }
+    }
+
+    /// Print each field or the empty filler if the field is not set.
+    fn print_format<F>(&self, f: F)
+    where
+        F: Fn(&Spec) -> Option<&'a str>,
+    {
+        for i in 0..self.format.len() {
+            if i > 0 {
+                print!("{}", self.separator);
+            }
+
+            let field = match f(&self.format[i]) {
+                Some(value) => value,
+                None => self.empty,
+            };
+
+            print!("{}", field);
+        }
+    }
+}
+
+/// Input processing parameters.
+struct Input {
+    separator: Sep,
+    ignore_case: bool,
+    check_order: CheckOrder,
+}
+
+impl Input {
+    fn new(separator: Sep, ignore_case: bool, check_order: CheckOrder) -> Input {
+        Input {
+            separator,
+            ignore_case,
+            check_order,
+        }
+    }
+
+    fn compare(&self, field1: Option<&str>, field2: Option<&str>) -> Ordering {
+        if let (Some(field1), Some(field2)) = (field1, field2) {
+            if self.ignore_case {
+                field1.to_lowercase().cmp(&field2.to_lowercase())
+            } else {
+                field1.cmp(field2)
+            }
+        } else {
+            match field1 {
+                Some(_) => Ordering::Greater,
+                None => match field2 {
+                    Some(_) => Ordering::Less,
+                    None => Ordering::Equal,
+                },
+            }
+        }
+    }
+}
+
+enum Spec {
+    Key,
+    Field(FileNum, usize),
+}
+
+impl Spec {
+    fn parse(format: &str) -> Spec {
+        let mut chars = format.chars();
+
+        let file_num = match chars.next() {
+            Some('0') => {
+                // Must be all alone without a field specifier.
+                if chars.next().is_none() {
+                    return Spec::Key;
+                }
+
+                crash!(1, "invalid field specifier: '{}'", format);
+            }
+            Some('1') => FileNum::File1,
+            Some('2') => FileNum::File2,
+            _ => crash!(1, "invalid file number in field spec: '{}'", format),
+        };
+
+        if let Some('.') = chars.next() {
+            return Spec::Field(file_num, parse_field_number(chars.as_str()));
+        }
+
+        crash!(1, "invalid field specifier: '{}'", format);
+    }
+}
+
+struct Line {
+    fields: Vec<String>,
+}
+
+impl Line {
+    fn new(string: String, separator: Sep) -> Line {
+        let fields = match separator {
+            Sep::Whitespaces => string.split_whitespace().map(String::from).collect(),
+            Sep::Char(sep) => string.split(sep).map(String::from).collect(),
+            Sep::Line => vec![string],
+        };
+
+        Line { fields }
+    }
+
+    /// Get field at index.
+    fn get_field(&self, index: usize) -> Option<&str> {
+        if index < self.fields.len() {
+            Some(&self.fields[index])
+        } else {
+            None
+        }
+    }
+}
+
+struct State<'a> {
+    key: usize,
+    file_name: &'a str,
+    file_num: FileNum,
+    print_unpaired: bool,
+    lines: Lines<Box<dyn BufRead + 'a>>,
+    seq: Vec<Line>,
+    max_fields: Option<usize>,
+    line_num: usize,
+    has_failed: bool,
+}
+
+impl<'a> State<'a> {
+    fn new(
+        file_num: FileNum,
+        name: &'a str,
+        stdin: &'a Stdin,
+        key: usize,
+        print_unpaired: bool,
+    ) -> State<'a> {
+        let f = if name == "-" {
+            Box::new(stdin.lock()) as Box<dyn BufRead>
+        } else {
+            match File::open(name) {
+                Ok(file) => Box::new(BufReader::new(file)) as Box<dyn BufRead>,
+                Err(err) => crash!(1, "{}: {}", name, err),
+            }
+        };
+
+        State {
+            key,
+            file_name: name,
+            file_num,
+            print_unpaired,
+            lines: f.lines(),
+            seq: Vec::new(),
+            max_fields: None,
+            line_num: 0,
+            has_failed: false,
+        }
+    }
+
+    /// Skip the current unpaired line.
+    fn skip_line(&mut self, input: &Input, repr: &Repr) {
+        if self.print_unpaired {
+            self.print_first_line(repr);
+        }
+
+        self.reset_next_line(input);
+    }
+
+    /// Keep reading line sequence until the key does not change, return
+    /// the first line whose key differs.
+    fn extend(&mut self, input: &Input) -> Option<Line> {
+        while let Some(line) = self.next_line(input) {
+            let diff = input.compare(self.get_current_key(), line.get_field(self.key));
+
+            if diff == Ordering::Equal {
+                self.seq.push(line);
+            } else {
+                return Some(line);
+            }
+        }
+
+        None
+    }
+
+    /// Print lines in the buffers as headers.
+    fn print_headers(&self, other: &State, repr: &Repr) {
+        if self.has_line() {
+            if other.has_line() {
+                self.combine(other, repr);
+            } else {
+                self.print_first_line(repr);
+            }
+        } else if other.has_line() {
+            other.print_first_line(repr);
+        }
+    }
+
+    /// Combine two line sequences.
+    fn combine(&self, other: &State, repr: &Repr) {
+        let key = self.get_current_key();
+
+        for line1 in &self.seq {
+            for line2 in &other.seq {
+                if repr.uses_format() {
+                    repr.print_format(|spec| match *spec {
+                        Spec::Key => key,
+                        Spec::Field(file_num, field_num) => {
+                            if file_num == self.file_num {
+                                return line1.get_field(field_num);
+                            }
+
+                            if file_num == other.file_num {
+                                return line2.get_field(field_num);
+                            }
+
+                            None
+                        }
+                    });
+                } else {
+                    repr.print_field(key);
+                    repr.print_fields(line1, self.key, self.max_fields);
+                    repr.print_fields(line2, other.key, other.max_fields);
+                }
+
+                println!();
+            }
+        }
+    }
+
+    /// Reset with the next line.
+    fn reset(&mut self, next_line: Option<Line>) {
+        self.seq.clear();
+
+        if let Some(line) = next_line {
+            self.seq.push(line);
+        }
+    }
+
+    fn reset_read_line(&mut self, input: &Input) {
+        let line = self.read_line(input.separator);
+        self.reset(line);
+    }
+
+    fn reset_next_line(&mut self, input: &Input) {
+        let line = self.next_line(input);
+        self.reset(line);
+    }
+
+    fn has_line(&self) -> bool {
+        !self.seq.is_empty()
+    }
+
+    fn initialize(&mut self, read_sep: Sep, autoformat: bool) {
+        if let Some(line) = self.read_line(read_sep) {
+            if autoformat {
+                self.max_fields = Some(line.fields.len());
+            }
+
+            self.seq.push(line);
+        }
+    }
+
+    fn finalize(&mut self, input: &Input, repr: &Repr) {
+        if self.has_line() && self.print_unpaired {
+            self.print_first_line(repr);
+
+            while let Some(line) = self.next_line(input) {
+                self.print_line(&line, repr);
+            }
+        }
+    }
+
+    /// Get the next line without the order check.
+    fn read_line(&mut self, sep: Sep) -> Option<Line> {
+        let value = self.lines.next()?;
+        self.line_num += 1;
+        Some(Line::new(crash_if_err!(1, value), sep))
+    }
+
+    /// Get the next line with the order check.
+    fn next_line(&mut self, input: &Input) -> Option<Line> {
+        let line = self.read_line(input.separator)?;
+
+        if input.check_order == CheckOrder::Disabled {
+            return Some(line);
+        }
+
+        let diff = input.compare(self.get_current_key(), line.get_field(self.key));
+
+        if diff == Ordering::Greater {
+            eprintln!("{}:{}: is not sorted", self.file_name, self.line_num);
+
+            // This is fatal if the check is enabled.
+            if input.check_order == CheckOrder::Enabled {
+                exit!(1);
+            }
+
+            self.has_failed = true;
+        }
+
+        Some(line)
+    }
+
+    /// Gets the key value of the lines stored in seq.
+    fn get_current_key(&self) -> Option<&str> {
+        self.seq[0].get_field(self.key)
+    }
+
+    fn print_line(&self, line: &Line, repr: &Repr) {
+        if repr.uses_format() {
+            repr.print_format(|spec| match *spec {
+                Spec::Key => line.get_field(self.key),
+                Spec::Field(file_num, field_num) => {
+                    if file_num == self.file_num {
+                        line.get_field(field_num)
+                    } else {
+                        None
+                    }
+                }
+            });
+        } else {
+            repr.print_field(line.get_field(self.key));
+            repr.print_fields(line, self.key, self.max_fields);
+        }
+
+        println!();
+    }
+
+    fn print_first_line(&self, repr: &Repr) {
+        self.print_line(&self.seq[0], repr);
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let matches = uu_app().get_matches_from(args);
+
+    let keys = parse_field_number_option(matches.value_of("j"));
+    let key1 = parse_field_number_option(matches.value_of("1"));
+    let key2 = parse_field_number_option(matches.value_of("2"));
+
+    let mut settings: Settings = Default::default();
+
+    let v_values = matches.values_of("v");
+    if v_values.is_some() {
+        settings.print_joined = false;
+    }
+
+    let unpaired = v_values
+        .unwrap_or_default()
+        .chain(matches.values_of("a").unwrap_or_default());
+    for file_num in unpaired {
+        match parse_file_number(file_num) {
+            FileNum::File1 => settings.print_unpaired1 = true,
+            FileNum::File2 => settings.print_unpaired2 = true,
+        }
+    }
+
+    settings.ignore_case = matches.is_present("i");
+    settings.key1 = get_field_number(keys, key1);
+    settings.key2 = get_field_number(keys, key2);
+
+    if let Some(value) = matches.value_of("t") {
+        settings.separator = match value.len() {
+            0 => Sep::Line,
+            1 => Sep::Char(value.chars().next().unwrap()),
+            _ => crash!(1, "multi-character tab {}", value),
+        };
+    }
+
+    if let Some(format) = matches.value_of("o") {
+        if format == "auto" {
+            settings.autoformat = true;
+        } else {
+            settings.format = format
+                .split(|c| c == ' ' || c == ',' || c == '\t')
+                .map(Spec::parse)
+                .collect();
+        }
+    }
+
+    if let Some(empty) = matches.value_of("e") {
+        settings.empty = empty.to_string();
+    }
+
+    if matches.is_present("nocheck-order") {
+        settings.check_order = CheckOrder::Disabled;
+    }
+
+    if matches.is_present("check-order") {
+        settings.check_order = CheckOrder::Enabled;
+    }
+
+    if matches.is_present("header") {
+        settings.headers = true;
+    }
+
+    let file1 = matches.value_of("file1").unwrap();
+    let file2 = matches.value_of("file2").unwrap();
+
+    if file1 == "-" && file2 == "-" {
+        crash!(1, "both files cannot be standard input");
+    }
+
+    exec(file1, file2, &settings)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(NAME)
+        .version(crate_version!())
+        .about(
+            "For each pair of input lines with identical join fields, write a line to
+standard output. The default join field is the first, delimited by blanks.
+
+When FILE1 or FILE2 (not both) is -, read standard input.",
+        )
+        .help_message("display this help and exit")
+        .version_message("display version and exit")
+        .arg(
+            Arg::with_name("a")
+                .short("a")
+                .multiple(true)
+                .number_of_values(1)
+                .possible_values(&["1", "2"])
+                .value_name("FILENUM")
+                .help(
+                    "also print unpairable lines from file FILENUM, where
+FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
+                ),
+        )
+        .arg(
+            Arg::with_name("v")
+                .short("v")
+                .multiple(true)
+                .number_of_values(1)
+                .possible_values(&["1", "2"])
+                .value_name("FILENUM")
+                .help("like -a FILENUM, but suppress joined output lines"),
+        )
+        .arg(
+            Arg::with_name("e")
+                .short("e")
+                .takes_value(true)
+                .value_name("EMPTY")
+                .help("replace missing input fields with EMPTY"),
+        )
+        .arg(
+            Arg::with_name("i")
+                .short("i")
+                .long("ignore-case")
+                .help("ignore differences in case when comparing fields"),
+        )
+        .arg(
+            Arg::with_name("j")
+                .short("j")
+                .takes_value(true)
+                .value_name("FIELD")
+                .help("equivalent to '-1 FIELD -2 FIELD'"),
+        )
+        .arg(
+            Arg::with_name("o")
+                .short("o")
+                .takes_value(true)
+                .value_name("FORMAT")
+                .help("obey FORMAT while constructing output line"),
+        )
+        .arg(
+            Arg::with_name("t")
+                .short("t")
+                .takes_value(true)
+                .value_name("CHAR")
+                .help("use CHAR as input and output field separator"),
+        )
+        .arg(
+            Arg::with_name("1")
+                .short("1")
+                .takes_value(true)
+                .value_name("FIELD")
+                .help("join on this FIELD of file 1"),
+        )
+        .arg(
+            Arg::with_name("2")
+                .short("2")
+                .takes_value(true)
+                .value_name("FIELD")
+                .help("join on this FIELD of file 2"),
+        )
+        .arg(Arg::with_name("check-order").long("check-order").help(
+            "check that the input is correctly sorted, \
+             even if all input lines are pairable",
+        ))
+        .arg(
+            Arg::with_name("nocheck-order")
+                .long("nocheck-order")
+                .help("do not check that the input is correctly sorted"),
+        )
+        .arg(Arg::with_name("header").long("header").help(
+            "treat the first line in each file as field headers, \
+             print them without trying to pair them",
+        ))
+        .arg(
+            Arg::with_name("file1")
+                .required(true)
+                .value_name("FILE1")
+                .hidden(true),
+        )
+        .arg(
+            Arg::with_name("file2")
+                .required(true)
+                .value_name("FILE2")
+                .hidden(true),
+        )
+}
+
+fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
+    let stdin = stdin();
+
+    let mut state1 = State::new(
+        FileNum::File1,
+        file1,
+        &stdin,
+        settings.key1,
+        settings.print_unpaired1,
+    );
+
+    let mut state2 = State::new(
+        FileNum::File2,
+        file2,
+        &stdin,
+        settings.key2,
+        settings.print_unpaired2,
+    );
+
+    let input = Input::new(
+        settings.separator,
+        settings.ignore_case,
+        settings.check_order,
+    );
+
+    let repr = Repr::new(
+        match settings.separator {
+            Sep::Char(sep) => sep,
+            _ => ' ',
+        },
+        &settings.format,
+        &settings.empty,
+    );
+
+    state1.initialize(settings.separator, settings.autoformat);
+    state2.initialize(settings.separator, settings.autoformat);
+
+    if settings.headers {
+        state1.print_headers(&state2, &repr);
+        state1.reset_read_line(&input);
+        state2.reset_read_line(&input);
+    }
+
+    while state1.has_line() && state2.has_line() {
+        let diff = input.compare(state1.get_current_key(), state2.get_current_key());
+
+        match diff {
+            Ordering::Less => {
+                state1.skip_line(&input, &repr);
+            }
+            Ordering::Greater => {
+                state2.skip_line(&input, &repr);
+            }
+            Ordering::Equal => {
+                let next_line1 = state1.extend(&input);
+                let next_line2 = state2.extend(&input);
+
+                if settings.print_joined {
+                    state1.combine(&state2, &repr);
+                }
+
+                state1.reset(next_line1);
+                state2.reset(next_line2);
+            }
+        }
+    }
+
+    state1.finalize(&input, &repr);
+    state2.finalize(&input, &repr);
+
+    (state1.has_failed || state2.has_failed) as i32
+}
+
+/// Check that keys for both files and for a particular file are not
+/// contradictory and return the key index.
+fn get_field_number(keys: Option<usize>, key: Option<usize>) -> usize {
+    if let Some(keys) = keys {
+        if let Some(key) = key {
+            if keys != key {
+                // Show zero-based field numbers as one-based.
+                crash!(1, "incompatible join fields {}, {}", keys + 1, key + 1);
+            }
+        }
+
+        return keys;
+    }
+
+    key.unwrap_or(0)
+}
+
+/// Parse the specified field string as a natural number and return
+/// the zero-based field number.
+fn parse_field_number(value: &str) -> usize {
+    match value.parse::<usize>() {
+        Ok(result) if result > 0 => result - 1,
+        _ => crash!(1, "invalid field number: '{}'", value),
+    }
+}
+
+fn parse_file_number(value: &str) -> FileNum {
+    match value {
+        "1" => FileNum::File1,
+        "2" => FileNum::File2,
+        value => crash!(1, "invalid file number: '{}'", value),
+    }
+}
+
+fn parse_field_number_option(value: Option<&str>) -> Option<usize> {
+    Some(parse_field_number(value?))
+}
+
+
\ No newline at end of file diff --git a/src/uu_kill/kill.rs.html b/src/uu_kill/kill.rs.html new file mode 100644 index 000000000..c8bfcb967 --- /dev/null +++ b/src/uu_kill/kill.rs.html @@ -0,0 +1,431 @@ +kill.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Maciej Dziardziel <fiedzia@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE file
+//  * that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) signalname pids
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use libc::{c_int, pid_t};
+use std::io::Error;
+use uucore::error::{UResult, USimpleError};
+use uucore::signals::ALL_SIGNALS;
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Send signal to processes or list information about signals.";
+
+pub mod options {
+    pub static PIDS_OR_SIGNALS: &str = "pids_of_signals";
+    pub static LIST: &str = "list";
+    pub static TABLE: &str = "table";
+    pub static TABLE_OLD: &str = "table_old";
+    pub static SIGNAL: &str = "signal";
+}
+
+#[derive(Clone, Copy)]
+pub enum Mode {
+    Kill,
+    Table,
+    List,
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+    let (args, obs_signal) = handle_obsolete(args);
+
+    let usage = format!("{} [OPTIONS]... PID...", uucore::execution_phrase());
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mode = if matches.is_present(options::TABLE) || matches.is_present(options::TABLE_OLD) {
+        Mode::Table
+    } else if matches.is_present(options::LIST) {
+        Mode::List
+    } else {
+        Mode::Kill
+    };
+
+    let pids_or_signals: Vec<String> = matches
+        .values_of(options::PIDS_OR_SIGNALS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    match mode {
+        Mode::Kill => {
+            let sig = match (obs_signal, matches.value_of(options::SIGNAL)) {
+                (Some(s), Some(_)) => s, // -s takes precedence
+                (Some(s), None) => s,
+                (None, Some(s)) => s.to_owned(),
+                (None, None) => "TERM".to_owned(),
+            };
+            kill(&sig, &pids_or_signals)
+        }
+        Mode::Table => {
+            table();
+            Ok(())
+        }
+        Mode::List => list(pids_or_signals.get(0).cloned()),
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::LIST)
+                .short("l")
+                .long(options::LIST)
+                .help("Lists signals")
+                .conflicts_with(options::TABLE)
+                .conflicts_with(options::TABLE_OLD),
+        )
+        .arg(
+            Arg::with_name(options::TABLE)
+                .short("t")
+                .long(options::TABLE)
+                .help("Lists table of signals"),
+        )
+        .arg(Arg::with_name(options::TABLE_OLD).short("L").hidden(true))
+        .arg(
+            Arg::with_name(options::SIGNAL)
+                .short("s")
+                .long(options::SIGNAL)
+                .help("Sends given signal")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::PIDS_OR_SIGNALS)
+                .hidden(true)
+                .multiple(true),
+        )
+}
+
+fn handle_obsolete(mut args: Vec<String>) -> (Vec<String>, Option<String>) {
+    let mut i = 0;
+    while i < args.len() {
+        // this is safe because slice is valid when it is referenced
+        let slice = &args[i].clone();
+        if slice.starts_with('-') && slice.chars().nth(1).map_or(false, |c| c.is_digit(10)) {
+            let val = &slice[1..];
+            match val.parse() {
+                Ok(num) => {
+                    if uucore::signals::is_signal(num) {
+                        args.remove(i);
+                        return (args, Some(val.to_owned()));
+                    }
+                }
+                Err(_) => break, /* getopts will error out for us */
+            }
+        }
+        i += 1;
+    }
+    (args, None)
+}
+
+fn table() {
+    let name_width = ALL_SIGNALS.iter().map(|n| n.len()).max().unwrap();
+
+    for (idx, signal) in ALL_SIGNALS.iter().enumerate() {
+        print!("{0: >#2} {1: <#2$}", idx, signal, name_width + 2);
+        if (idx + 1) % 7 == 0 {
+            println!();
+        }
+    }
+    println!();
+}
+
+fn print_signal(signal_name_or_value: &str) -> UResult<()> {
+    for (value, &signal) in ALL_SIGNALS.iter().enumerate() {
+        if signal == signal_name_or_value || (format!("SIG{}", signal)) == signal_name_or_value {
+            println!("{}", value);
+            return Ok(());
+        } else if signal_name_or_value == value.to_string() {
+            println!("{}", signal);
+            return Ok(());
+        }
+    }
+    Err(USimpleError::new(
+        1,
+        format!("unknown signal name {}", signal_name_or_value),
+    ))
+}
+
+fn print_signals() {
+    let mut pos = 0;
+    for (idx, signal) in ALL_SIGNALS.iter().enumerate() {
+        pos += signal.len();
+        print!("{}", signal);
+        if idx > 0 && pos > 73 {
+            println!();
+            pos = 0;
+        } else {
+            pos += 1;
+            print!(" ");
+        }
+    }
+}
+
+fn list(arg: Option<String>) -> UResult<()> {
+    match arg {
+        Some(ref x) => print_signal(x),
+        None => {
+            print_signals();
+            Ok(())
+        }
+    }
+}
+
+fn kill(signalname: &str, pids: &[String]) -> UResult<()> {
+    let optional_signal_value = uucore::signals::signal_by_name_or_value(signalname);
+    let signal_value = match optional_signal_value {
+        Some(x) => x,
+        None => {
+            return Err(USimpleError::new(
+                1,
+                format!("unknown signal name {}", signalname),
+            ));
+        }
+    };
+    for pid in pids {
+        match pid.parse::<usize>() {
+            Ok(x) => {
+                if unsafe { libc::kill(x as pid_t, signal_value as c_int) } != 0 {
+                    show!(USimpleError::new(1, format!("{}", Error::last_os_error())));
+                }
+            }
+            Err(e) => {
+                return Err(USimpleError::new(
+                    1,
+                    format!("failed to parse argument {}: {}", pid, e),
+                ));
+            }
+        };
+    }
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_link/link.rs.html b/src/uu_link/link.rs.html new file mode 100644 index 000000000..c229c81c6 --- /dev/null +++ b/src/uu_link/link.rs.html @@ -0,0 +1,135 @@ +link.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Gehring <mg@ebfe.org>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs::hard_link;
+use std::io::Error;
+use std::path::Path;
+
+static ABOUT: &str = "Call the link function to create a link named FILE2 to an existing FILE1.";
+
+pub mod options {
+    pub static FILES: &str = "FILES";
+}
+
+fn usage() -> String {
+    format!("{0} FILE1 FILE2", uucore::execution_phrase())
+}
+
+pub fn normalize_error_message(e: Error) -> String {
+    match e.raw_os_error() {
+        Some(2) => String::from("No such file or directory (os error 2)"),
+        _ => format!("{}", e),
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let files: Vec<_> = matches
+        .values_of_os(options::FILES)
+        .unwrap_or_default()
+        .collect();
+    let old = Path::new(files[0]);
+    let new = Path::new(files[1]);
+
+    match hard_link(old, new) {
+        Ok(_) => 0,
+        Err(err) => {
+            show_error!("{}", normalize_error_message(err));
+            1
+        }
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::FILES)
+                .hidden(true)
+                .required(true)
+                .min_values(2)
+                .max_values(2)
+                .takes_value(true),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_ln/ln.rs.html b/src/uu_ln/ln.rs.html new file mode 100644 index 000000000..ace1ae01e --- /dev/null +++ b/src/uu_ln/ln.rs.html @@ -0,0 +1,1053 @@ +ln.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Joseph Crail <jbcrail@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) srcpath targetpath EEXIST
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use uucore::error::{UError, UResult};
+
+use std::borrow::Cow;
+use std::error::Error;
+use std::ffi::OsStr;
+use std::fmt::Display;
+use std::fs;
+
+use std::io::{stdin, Result};
+#[cfg(any(unix, target_os = "redox"))]
+use std::os::unix::fs::symlink;
+#[cfg(windows)]
+use std::os::windows::fs::{symlink_dir, symlink_file};
+use std::path::{Path, PathBuf};
+use uucore::backup_control::{self, BackupMode};
+use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
+
+pub struct Settings {
+    overwrite: OverwriteMode,
+    backup: BackupMode,
+    suffix: String,
+    symbolic: bool,
+    relative: bool,
+    target_dir: Option<String>,
+    no_target_dir: bool,
+    no_dereference: bool,
+    verbose: bool,
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub enum OverwriteMode {
+    NoClobber,
+    Interactive,
+    Force,
+}
+
+#[derive(Debug)]
+enum LnError {
+    TargetIsDirectory(String),
+    SomeLinksFailed,
+    FailedToLink(String),
+    MissingDestination(String),
+    ExtraOperand(String),
+    InvalidBackupMode(String),
+}
+
+impl Display for LnError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Self::TargetIsDirectory(s) => write!(f, "target '{}' is not a directory", s),
+            Self::FailedToLink(s) => write!(f, "failed to link '{}'", s),
+            Self::SomeLinksFailed => write!(f, "some links failed to create"),
+            Self::MissingDestination(s) => {
+                write!(f, "missing destination file operand after '{}'", s)
+            }
+            Self::ExtraOperand(s) => write!(
+                f,
+                "extra operand '{}'\nTry '{} --help' for more information.",
+                s,
+                uucore::execution_phrase()
+            ),
+            Self::InvalidBackupMode(s) => write!(f, "{}", s),
+        }
+    }
+}
+
+impl Error for LnError {}
+
+impl UError for LnError {
+    fn code(&self) -> i32 {
+        match self {
+            Self::TargetIsDirectory(_) => 1,
+            Self::SomeLinksFailed => 1,
+            Self::FailedToLink(_) => 1,
+            Self::MissingDestination(_) => 1,
+            Self::ExtraOperand(_) => 1,
+            Self::InvalidBackupMode(_) => 1,
+        }
+    }
+}
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [-T] TARGET LINK_NAME   (1st form)
+       {0} [OPTION]... TARGET                  (2nd form)
+       {0} [OPTION]... TARGET... DIRECTORY     (3rd form)
+       {0} [OPTION]... -t DIRECTORY TARGET...  (4th form)",
+        uucore::execution_phrase()
+    )
+}
+
+fn long_usage() -> String {
+    String::from(
+        " In the 1st form, create a link to TARGET with the name LINK_NAME.
+        In the 2nd form, create a link to TARGET in the current directory.
+        In the 3rd and 4th forms, create links to each TARGET in DIRECTORY.
+        Create hard links by default, symbolic links with --symbolic.
+        By default, each destination (name of new link) should not already exist.
+        When creating hard links, each TARGET must exist.  Symbolic links
+        can hold arbitrary text; if later resolved, a relative link is
+        interpreted in relation to its parent directory.
+        ",
+    )
+}
+
+static ABOUT: &str = "change file owner and group";
+
+mod options {
+    pub const BACKUP_NO_ARG: &str = "b";
+    pub const BACKUP: &str = "backup";
+    pub const FORCE: &str = "force";
+    pub const INTERACTIVE: &str = "interactive";
+    pub const NO_DEREFERENCE: &str = "no-dereference";
+    pub const SYMBOLIC: &str = "symbolic";
+    pub const SUFFIX: &str = "suffix";
+    pub const TARGET_DIRECTORY: &str = "target-directory";
+    pub const NO_TARGET_DIRECTORY: &str = "no-target-directory";
+    pub const RELATIVE: &str = "relative";
+    pub const VERBOSE: &str = "verbose";
+}
+
+static ARG_FILES: &str = "files";
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+    let long_usage = long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&*format!(
+            "{}\n{}",
+            long_usage,
+            backup_control::BACKUP_CONTROL_LONG_HELP
+        ))
+        .get_matches_from(args);
+
+    /* the list of files */
+
+    let paths: Vec<PathBuf> = matches
+        .values_of(ARG_FILES)
+        .unwrap()
+        .map(PathBuf::from)
+        .collect();
+
+    let overwrite_mode = if matches.is_present(options::FORCE) {
+        OverwriteMode::Force
+    } else if matches.is_present(options::INTERACTIVE) {
+        OverwriteMode::Interactive
+    } else {
+        OverwriteMode::NoClobber
+    };
+
+    let backup_mode = backup_control::determine_backup_mode(
+        matches.is_present(options::BACKUP_NO_ARG),
+        matches.is_present(options::BACKUP),
+        matches.value_of(options::BACKUP),
+    );
+    let backup_mode = match backup_mode {
+        Err(err) => {
+            return Err(LnError::InvalidBackupMode(err).into());
+        }
+        Ok(mode) => mode,
+    };
+
+    let backup_suffix = backup_control::determine_backup_suffix(matches.value_of(options::SUFFIX));
+
+    let settings = Settings {
+        overwrite: overwrite_mode,
+        backup: backup_mode,
+        suffix: backup_suffix,
+        symbolic: matches.is_present(options::SYMBOLIC),
+        relative: matches.is_present(options::RELATIVE),
+        target_dir: matches
+            .value_of(options::TARGET_DIRECTORY)
+            .map(String::from),
+        no_target_dir: matches.is_present(options::NO_TARGET_DIRECTORY),
+        no_dereference: matches.is_present(options::NO_DEREFERENCE),
+        verbose: matches.is_present(options::VERBOSE),
+    };
+
+    exec(&paths[..], &settings)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::BACKUP)
+                .long(options::BACKUP)
+                .help("make a backup of each existing destination file")
+                .takes_value(true)
+                .require_equals(true)
+                .min_values(0)
+                .value_name("CONTROL"),
+        )
+        .arg(
+            Arg::with_name(options::BACKUP_NO_ARG)
+                .short(options::BACKUP_NO_ARG)
+                .help("like --backup but does not accept an argument"),
+        )
+        // TODO: opts.arg(
+        //    Arg::with_name(("d", "directory", "allow users with appropriate privileges to attempt \
+        //                                       to make hard links to directories");
+        .arg(
+            Arg::with_name(options::FORCE)
+                .short("f")
+                .long(options::FORCE)
+                .help("remove existing destination files"),
+        )
+        .arg(
+            Arg::with_name(options::INTERACTIVE)
+                .short("i")
+                .long(options::INTERACTIVE)
+                .help("prompt whether to remove existing destination files"),
+        )
+        .arg(
+            Arg::with_name(options::NO_DEREFERENCE)
+                .short("n")
+                .long(options::NO_DEREFERENCE)
+                .help(
+                    "treat LINK_NAME as a normal file if it is a \
+                     symbolic link to a directory",
+                ),
+        )
+        // TODO: opts.arg(
+        //    Arg::with_name(("L", "logical", "dereference TARGETs that are symbolic links");
+        //
+        // TODO: opts.arg(
+        //    Arg::with_name(("P", "physical", "make hard links directly to symbolic links");
+        .arg(
+            Arg::with_name(options::SYMBOLIC)
+                .short("s")
+                .long("symbolic")
+                .help("make symbolic links instead of hard links")
+                // override added for https://github.com/uutils/coreutils/issues/2359
+                .overrides_with(options::SYMBOLIC),
+        )
+        .arg(
+            Arg::with_name(options::SUFFIX)
+                .short("S")
+                .long(options::SUFFIX)
+                .help("override the usual backup suffix")
+                .value_name("SUFFIX")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::TARGET_DIRECTORY)
+                .short("t")
+                .long(options::TARGET_DIRECTORY)
+                .help("specify the DIRECTORY in which to create the links")
+                .value_name("DIRECTORY")
+                .conflicts_with(options::NO_TARGET_DIRECTORY),
+        )
+        .arg(
+            Arg::with_name(options::NO_TARGET_DIRECTORY)
+                .short("T")
+                .long(options::NO_TARGET_DIRECTORY)
+                .help("treat LINK_NAME as a normal file always"),
+        )
+        .arg(
+            Arg::with_name(options::RELATIVE)
+                .short("r")
+                .long(options::RELATIVE)
+                .help("create symbolic links relative to link location")
+                .requires(options::SYMBOLIC),
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE)
+                .short("v")
+                .long(options::VERBOSE)
+                .help("print name of each linked file"),
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .required(true)
+                .min_values(1),
+        )
+}
+
+fn exec(files: &[PathBuf], settings: &Settings) -> UResult<()> {
+    // Handle cases where we create links in a directory first.
+    if let Some(ref name) = settings.target_dir {
+        // 4th form: a directory is specified by -t.
+        return link_files_in_dir(files, &PathBuf::from(name), settings);
+    }
+    if !settings.no_target_dir {
+        if files.len() == 1 {
+            // 2nd form: the target directory is the current directory.
+            return link_files_in_dir(files, &PathBuf::from("."), settings);
+        }
+        let last_file = &PathBuf::from(files.last().unwrap());
+        if files.len() > 2 || last_file.is_dir() {
+            // 3rd form: create links in the last argument.
+            return link_files_in_dir(&files[0..files.len() - 1], last_file, settings);
+        }
+    }
+
+    // 1st form. Now there should be only two operands, but if -T is
+    // specified we may have a wrong number of operands.
+    if files.len() == 1 {
+        return Err(LnError::MissingDestination(files[0].to_string_lossy().into()).into());
+    }
+    if files.len() > 2 {
+        return Err(LnError::ExtraOperand(files[2].display().to_string()).into());
+    }
+    assert!(!files.is_empty());
+
+    match link(&files[0], &files[1], settings) {
+        Ok(_) => Ok(()),
+        Err(e) => Err(LnError::FailedToLink(e.to_string()).into()),
+    }
+}
+
+fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) -> UResult<()> {
+    if !target_dir.is_dir() {
+        return Err(LnError::TargetIsDirectory(target_dir.display().to_string()).into());
+    }
+
+    let mut all_successful = true;
+    for srcpath in files.iter() {
+        let targetpath =
+            if settings.no_dereference && matches!(settings.overwrite, OverwriteMode::Force) {
+                // In that case, we don't want to do link resolution
+                // We need to clean the target
+                if is_symlink(target_dir) {
+                    if target_dir.is_file() {
+                        if let Err(e) = fs::remove_file(target_dir) {
+                            show_error!("Could not update {}: {}", target_dir.display(), e)
+                        };
+                    }
+                    if target_dir.is_dir() {
+                        // Not sure why but on Windows, the symlink can be
+                        // considered as a dir
+                        // See test_ln::test_symlink_no_deref_dir
+                        if let Err(e) = fs::remove_dir(target_dir) {
+                            show_error!("Could not update {}: {}", target_dir.display(), e)
+                        };
+                    }
+                }
+                target_dir.to_path_buf()
+            } else {
+                match srcpath.as_os_str().to_str() {
+                    Some(name) => {
+                        match Path::new(name).file_name() {
+                            Some(basename) => target_dir.join(basename),
+                            // This can be None only for "." or "..". Trying
+                            // to create a link with such name will fail with
+                            // EEXIST, which agrees with the behavior of GNU
+                            // coreutils.
+                            None => target_dir.join(name),
+                        }
+                    }
+                    None => {
+                        show_error!(
+                            "cannot stat '{}': No such file or directory",
+                            srcpath.display()
+                        );
+                        all_successful = false;
+                        continue;
+                    }
+                }
+            };
+
+        if let Err(e) = link(srcpath, &targetpath, settings) {
+            show_error!(
+                "cannot link '{}' to '{}': {}",
+                targetpath.display(),
+                srcpath.display(),
+                e
+            );
+            all_successful = false;
+        }
+    }
+    if all_successful {
+        Ok(())
+    } else {
+        Err(LnError::SomeLinksFailed.into())
+    }
+}
+
+fn relative_path<'a>(src: &Path, dst: &Path) -> Result<Cow<'a, Path>> {
+    let src_abs = canonicalize(src, MissingHandling::Normal, ResolveMode::Logical)?;
+    let mut dst_abs = canonicalize(
+        dst.parent().unwrap(),
+        MissingHandling::Normal,
+        ResolveMode::Logical,
+    )?;
+    dst_abs.push(dst.components().last().unwrap());
+    let suffix_pos = src_abs
+        .components()
+        .zip(dst_abs.components())
+        .take_while(|(s, d)| s == d)
+        .count();
+
+    let src_iter = src_abs.components().skip(suffix_pos).map(|x| x.as_os_str());
+
+    let mut result: PathBuf = dst_abs
+        .components()
+        .skip(suffix_pos + 1)
+        .map(|_| OsStr::new(".."))
+        .chain(src_iter)
+        .collect();
+    if result.as_os_str().is_empty() {
+        result.push(".");
+    }
+    Ok(result.into())
+}
+
+fn link(src: &Path, dst: &Path, settings: &Settings) -> Result<()> {
+    let mut backup_path = None;
+    let source: Cow<'_, Path> = if settings.relative {
+        relative_path(src, dst)?
+    } else {
+        src.into()
+    };
+
+    if is_symlink(dst) || dst.exists() {
+        match settings.overwrite {
+            OverwriteMode::NoClobber => {}
+            OverwriteMode::Interactive => {
+                print!("{}: overwrite '{}'? ", uucore::util_name(), dst.display());
+                if !read_yes() {
+                    return Ok(());
+                }
+                fs::remove_file(dst)?
+            }
+            OverwriteMode::Force => fs::remove_file(dst)?,
+        };
+
+        backup_path = match settings.backup {
+            BackupMode::NoBackup => None,
+            BackupMode::SimpleBackup => Some(simple_backup_path(dst, &settings.suffix)),
+            BackupMode::NumberedBackup => Some(numbered_backup_path(dst)),
+            BackupMode::ExistingBackup => Some(existing_backup_path(dst, &settings.suffix)),
+        };
+        if let Some(ref p) = backup_path {
+            fs::rename(dst, p)?;
+        }
+    }
+
+    if settings.symbolic {
+        symlink(&source, dst)?;
+    } else {
+        fs::hard_link(&source, dst)?;
+    }
+
+    if settings.verbose {
+        print!("'{}' -> '{}'", dst.display(), &source.display());
+        match backup_path {
+            Some(path) => println!(" (backup: '{}')", path.display()),
+            None => println!(),
+        }
+    }
+    Ok(())
+}
+
+fn read_yes() -> bool {
+    let mut s = String::new();
+    match stdin().read_line(&mut s) {
+        Ok(_) => match s.char_indices().next() {
+            Some((_, x)) => x == 'y' || x == 'Y',
+            _ => false,
+        },
+        _ => false,
+    }
+}
+
+fn simple_backup_path(path: &Path, suffix: &str) -> PathBuf {
+    let mut p = path.as_os_str().to_str().unwrap().to_owned();
+    p.push_str(suffix);
+    PathBuf::from(p)
+}
+
+fn numbered_backup_path(path: &Path) -> PathBuf {
+    let mut i: u64 = 1;
+    loop {
+        let new_path = simple_backup_path(path, &format!(".~{}~", i));
+        if !new_path.exists() {
+            return new_path;
+        }
+        i += 1;
+    }
+}
+
+fn existing_backup_path(path: &Path, suffix: &str) -> PathBuf {
+    let test_path = simple_backup_path(path, &".~1~".to_owned());
+    if test_path.exists() {
+        return numbered_backup_path(path);
+    }
+    simple_backup_path(path, suffix)
+}
+
+#[cfg(windows)]
+pub fn symlink<P1: AsRef<Path>, P2: AsRef<Path>>(src: P1, dst: P2) -> Result<()> {
+    if src.as_ref().is_dir() {
+        symlink_dir(src, dst)
+    } else {
+        symlink_file(src, dst)
+    }
+}
+
+pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool {
+    match fs::symlink_metadata(path) {
+        Ok(m) => m.file_type().is_symlink(),
+        Err(_) => false,
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_logname/logname.rs.html b/src/uu_logname/logname.rs.html new file mode 100644 index 000000000..46a712043 --- /dev/null +++ b/src/uu_logname/logname.rs.html @@ -0,0 +1,129 @@ +logname.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+/* last synced with: logname (GNU coreutils) 8.22 */
+
+// spell-checker:ignore (ToDO) getlogin userlogin
+
+#[macro_use]
+extern crate uucore;
+
+use std::ffi::CStr;
+use uucore::InvalidEncodingHandling;
+
+use clap::{crate_version, App};
+
+extern "C" {
+    // POSIX requires using getlogin (or equivalent code)
+    pub fn getlogin() -> *const libc::c_char;
+}
+
+fn get_userlogin() -> Option<String> {
+    unsafe {
+        let login: *const libc::c_char = getlogin();
+        if login.is_null() {
+            None
+        } else {
+            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
+        }
+    }
+}
+
+static SUMMARY: &str = "Print user's login name";
+
+fn usage() -> String {
+    uucore::execution_phrase()
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+    let _ = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    match get_userlogin() {
+        Some(userlogin) => println!("{}", userlogin),
+        None => show_error!("no login name"),
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(SUMMARY)
+}
+
+
\ No newline at end of file diff --git a/src/uu_ls/ls.rs.html b/src/uu_ls/ls.rs.html new file mode 100644 index 000000000..21423c8b8 --- /dev/null +++ b/src/uu_ls/ls.rs.html @@ -0,0 +1,3767 @@ +ls.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jeremiah Peschka <jeremiah.peschka@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) cpio svgz webm somegroup nlink rmvb xspf
+
+#[macro_use]
+extern crate uucore;
+#[cfg(unix)]
+#[macro_use]
+extern crate lazy_static;
+
+mod quoting_style;
+
+use clap::{crate_version, App, Arg};
+use globset::{self, Glob, GlobSet, GlobSetBuilder};
+use lscolors::LsColors;
+use number_prefix::NumberPrefix;
+use once_cell::unsync::OnceCell;
+use quoting_style::{escape_name, QuotingStyle};
+#[cfg(windows)]
+use std::os::windows::fs::MetadataExt;
+use std::{
+    cmp::Reverse,
+    error::Error,
+    fmt::Display,
+    fs::{self, DirEntry, FileType, Metadata},
+    io::{stdout, BufWriter, Stdout, Write},
+    path::{Path, PathBuf},
+    time::{SystemTime, UNIX_EPOCH},
+};
+#[cfg(unix)]
+use std::{
+    collections::HashMap,
+    os::unix::fs::{FileTypeExt, MetadataExt},
+    time::Duration,
+};
+use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
+use uucore::error::{set_exit_code, FromIo, UError, UResult};
+
+use unicode_width::UnicodeWidthStr;
+#[cfg(unix)]
+use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
+use uucore::{fs::display_permissions, version_cmp::version_cmp};
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+pub mod options {
+
+    pub mod format {
+        pub static ONE_LINE: &str = "1";
+        pub static LONG: &str = "long";
+        pub static COLUMNS: &str = "C";
+        pub static ACROSS: &str = "x";
+        pub static COMMAS: &str = "m";
+        pub static LONG_NO_OWNER: &str = "g";
+        pub static LONG_NO_GROUP: &str = "o";
+        pub static LONG_NUMERIC_UID_GID: &str = "numeric-uid-gid";
+    }
+
+    pub mod files {
+        pub static ALL: &str = "all";
+        pub static ALMOST_ALL: &str = "almost-all";
+    }
+
+    pub mod sort {
+        pub static SIZE: &str = "S";
+        pub static TIME: &str = "t";
+        pub static NONE: &str = "U";
+        pub static VERSION: &str = "v";
+        pub static EXTENSION: &str = "X";
+    }
+
+    pub mod time {
+        pub static ACCESS: &str = "u";
+        pub static CHANGE: &str = "c";
+    }
+
+    pub mod size {
+        pub static HUMAN_READABLE: &str = "human-readable";
+        pub static SI: &str = "si";
+    }
+
+    pub mod quoting {
+        pub static ESCAPE: &str = "escape";
+        pub static LITERAL: &str = "literal";
+        pub static C: &str = "quote-name";
+    }
+
+    pub mod indicator_style {
+        pub static SLASH: &str = "p";
+        pub static FILE_TYPE: &str = "file-type";
+        pub static CLASSIFY: &str = "classify";
+    }
+
+    pub mod dereference {
+        pub static ALL: &str = "dereference";
+        pub static ARGS: &str = "dereference-command-line";
+        pub static DIR_ARGS: &str = "dereference-command-line-symlink-to-dir";
+    }
+
+    pub static QUOTING_STYLE: &str = "quoting-style";
+    pub static HIDE_CONTROL_CHARS: &str = "hide-control-chars";
+    pub static SHOW_CONTROL_CHARS: &str = "show-control-chars";
+    pub static WIDTH: &str = "width";
+    pub static AUTHOR: &str = "author";
+    pub static NO_GROUP: &str = "no-group";
+    pub static FORMAT: &str = "format";
+    pub static SORT: &str = "sort";
+    pub static TIME: &str = "time";
+    pub static IGNORE_BACKUPS: &str = "ignore-backups";
+    pub static DIRECTORY: &str = "directory";
+    pub static INODE: &str = "inode";
+    pub static REVERSE: &str = "reverse";
+    pub static RECURSIVE: &str = "recursive";
+    pub static COLOR: &str = "color";
+    pub static PATHS: &str = "paths";
+    pub static INDICATOR_STYLE: &str = "indicator-style";
+    pub static TIME_STYLE: &str = "time-style";
+    pub static FULL_TIME: &str = "full-time";
+    pub static HIDE: &str = "hide";
+    pub static IGNORE: &str = "ignore";
+}
+
+const DEFAULT_TERM_WIDTH: u16 = 80;
+
+#[derive(Debug)]
+enum LsError {
+    InvalidLineWidth(String),
+    NoMetadata(PathBuf),
+}
+
+impl UError for LsError {
+    fn code(&self) -> i32 {
+        match self {
+            LsError::InvalidLineWidth(_) => 2,
+            LsError::NoMetadata(_) => 1,
+        }
+    }
+}
+
+impl Error for LsError {}
+
+impl Display for LsError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            LsError::InvalidLineWidth(s) => write!(f, "invalid line width: '{}'", s),
+            LsError::NoMetadata(p) => write!(f, "could not open file: '{}'", p.display()),
+        }
+    }
+}
+
+#[derive(PartialEq, Eq)]
+enum Format {
+    Columns,
+    Long,
+    OneLine,
+    Across,
+    Commas,
+}
+
+enum Sort {
+    None,
+    Name,
+    Size,
+    Time,
+    Version,
+    Extension,
+}
+
+enum SizeFormat {
+    Bytes,
+    Binary,  // Powers of 1024, --human-readable, -h
+    Decimal, // Powers of 1000, --si
+}
+
+#[derive(PartialEq, Eq)]
+enum Files {
+    All,
+    AlmostAll,
+    Normal,
+}
+
+enum Time {
+    Modification,
+    Access,
+    Change,
+    Birth,
+}
+
+#[derive(Debug)]
+enum TimeStyle {
+    FullIso,
+    LongIso,
+    Iso,
+    Locale,
+}
+
+enum Dereference {
+    None,
+    DirArgs,
+    Args,
+    All,
+}
+
+#[derive(PartialEq, Eq)]
+enum IndicatorStyle {
+    None,
+    Slash,
+    FileType,
+    Classify,
+}
+
+struct Config {
+    format: Format,
+    files: Files,
+    sort: Sort,
+    recursive: bool,
+    reverse: bool,
+    dereference: Dereference,
+    ignore_patterns: GlobSet,
+    size_format: SizeFormat,
+    directory: bool,
+    time: Time,
+    #[cfg(unix)]
+    inode: bool,
+    color: Option<LsColors>,
+    long: LongFormat,
+    width: u16,
+    quoting_style: QuotingStyle,
+    indicator_style: IndicatorStyle,
+    time_style: TimeStyle,
+}
+
+// Fields that can be removed or added to the long format
+struct LongFormat {
+    author: bool,
+    group: bool,
+    owner: bool,
+    #[cfg(unix)]
+    numeric_uid_gid: bool,
+}
+
+impl Config {
+    #[allow(clippy::cognitive_complexity)]
+    fn from(options: clap::ArgMatches) -> UResult<Config> {
+        let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) {
+            (
+                match format_ {
+                    "long" | "verbose" => Format::Long,
+                    "single-column" => Format::OneLine,
+                    "columns" | "vertical" => Format::Columns,
+                    "across" | "horizontal" => Format::Across,
+                    "commas" => Format::Commas,
+                    // below should never happen as clap already restricts the values.
+                    _ => unreachable!("Invalid field for --format"),
+                },
+                Some(options::FORMAT),
+            )
+        } else if options.is_present(options::format::LONG) {
+            (Format::Long, Some(options::format::LONG))
+        } else if options.is_present(options::format::ACROSS) {
+            (Format::Across, Some(options::format::ACROSS))
+        } else if options.is_present(options::format::COMMAS) {
+            (Format::Commas, Some(options::format::COMMAS))
+        } else if options.is_present(options::format::COLUMNS) {
+            (Format::Columns, Some(options::format::COLUMNS))
+        } else if atty::is(atty::Stream::Stdout) {
+            (Format::Columns, None)
+        } else {
+            (Format::OneLine, None)
+        };
+
+        // The -o, -n and -g options are tricky. They cannot override with each
+        // other because it's possible to combine them. For example, the option
+        // -og should hide both owner and group. Furthermore, they are not
+        // reset if -l or --format=long is used. So these should just show the
+        // group: -gl or "-g --format=long". Finally, they are also not reset
+        // when switching to a different format option in-between like this:
+        // -ogCl or "-og --format=vertical --format=long".
+        //
+        // -1 has a similar issue: it does nothing if the format is long. This
+        // actually makes it distinct from the --format=singe-column option,
+        // which always applies.
+        //
+        // The idea here is to not let these options override with the other
+        // options, but manually whether they have an index that's greater than
+        // the other format options. If so, we set the appropriate format.
+        if format != Format::Long {
+            let idx = opt
+                .and_then(|opt| options.indices_of(opt).map(|x| x.max().unwrap()))
+                .unwrap_or(0);
+            if [
+                options::format::LONG_NO_OWNER,
+                options::format::LONG_NO_GROUP,
+                options::format::LONG_NUMERIC_UID_GID,
+                options::FULL_TIME,
+            ]
+            .iter()
+            .flat_map(|opt| options.indices_of(opt))
+            .flatten()
+            .any(|i| i >= idx)
+            {
+                format = Format::Long;
+            } else if let Some(mut indices) = options.indices_of(options::format::ONE_LINE) {
+                if indices.any(|i| i > idx) {
+                    format = Format::OneLine;
+                }
+            }
+        }
+
+        let files = if options.is_present(options::files::ALL) {
+            Files::All
+        } else if options.is_present(options::files::ALMOST_ALL) {
+            Files::AlmostAll
+        } else {
+            Files::Normal
+        };
+
+        let sort = if let Some(field) = options.value_of(options::SORT) {
+            match field {
+                "none" => Sort::None,
+                "name" => Sort::Name,
+                "time" => Sort::Time,
+                "size" => Sort::Size,
+                "version" => Sort::Version,
+                "extension" => Sort::Extension,
+                // below should never happen as clap already restricts the values.
+                _ => unreachable!("Invalid field for --sort"),
+            }
+        } else if options.is_present(options::sort::TIME) {
+            Sort::Time
+        } else if options.is_present(options::sort::SIZE) {
+            Sort::Size
+        } else if options.is_present(options::sort::NONE) {
+            Sort::None
+        } else if options.is_present(options::sort::VERSION) {
+            Sort::Version
+        } else if options.is_present(options::sort::EXTENSION) {
+            Sort::Extension
+        } else {
+            Sort::Name
+        };
+
+        let time = if let Some(field) = options.value_of(options::TIME) {
+            match field {
+                "ctime" | "status" => Time::Change,
+                "access" | "atime" | "use" => Time::Access,
+                "birth" | "creation" => Time::Birth,
+                // below should never happen as clap already restricts the values.
+                _ => unreachable!("Invalid field for --time"),
+            }
+        } else if options.is_present(options::time::ACCESS) {
+            Time::Access
+        } else if options.is_present(options::time::CHANGE) {
+            Time::Change
+        } else {
+            Time::Modification
+        };
+
+        let needs_color = match options.value_of(options::COLOR) {
+            None => options.is_present(options::COLOR),
+            Some(val) => match val {
+                "" | "always" | "yes" | "force" => true,
+                "auto" | "tty" | "if-tty" => atty::is(atty::Stream::Stdout),
+                /* "never" | "no" | "none" | */ _ => false,
+            },
+        };
+
+        let color = if needs_color {
+            Some(LsColors::from_env().unwrap_or_default())
+        } else {
+            None
+        };
+
+        let size_format = if options.is_present(options::size::HUMAN_READABLE) {
+            SizeFormat::Binary
+        } else if options.is_present(options::size::SI) {
+            SizeFormat::Decimal
+        } else {
+            SizeFormat::Bytes
+        };
+
+        let long = {
+            let author = options.is_present(options::AUTHOR);
+            let group = !options.is_present(options::NO_GROUP)
+                && !options.is_present(options::format::LONG_NO_GROUP);
+            let owner = !options.is_present(options::format::LONG_NO_OWNER);
+            #[cfg(unix)]
+            let numeric_uid_gid = options.is_present(options::format::LONG_NUMERIC_UID_GID);
+            LongFormat {
+                author,
+                group,
+                owner,
+                #[cfg(unix)]
+                numeric_uid_gid,
+            }
+        };
+
+        let width = match options.value_of(options::WIDTH) {
+            Some(x) => match x.parse::<u16>() {
+                Ok(u) => u,
+                Err(_) => return Err(LsError::InvalidLineWidth(x.into()).into()),
+            },
+            None => match termsize::get() {
+                Some(size) => size.cols,
+                None => match std::env::var("COLUMNS") {
+                    Ok(columns) => match columns.parse() {
+                        Ok(columns) => columns,
+                        Err(_) => {
+                            show_error!(
+                                "ignoring invalid width in environment variable COLUMNS: '{}'",
+                                columns
+                            );
+                            DEFAULT_TERM_WIDTH
+                        }
+                    },
+                    Err(_) => DEFAULT_TERM_WIDTH,
+                },
+            },
+        };
+
+        #[allow(clippy::needless_bool)]
+        let show_control = if options.is_present(options::HIDE_CONTROL_CHARS) {
+            false
+        } else if options.is_present(options::SHOW_CONTROL_CHARS) || atty::is(atty::Stream::Stdout)
+        {
+            true
+        } else {
+            false
+        };
+
+        let quoting_style = if let Some(style) = options.value_of(options::QUOTING_STYLE) {
+            match style {
+                "literal" => QuotingStyle::Literal { show_control },
+                "shell" => QuotingStyle::Shell {
+                    escape: false,
+                    always_quote: false,
+                    show_control,
+                },
+                "shell-always" => QuotingStyle::Shell {
+                    escape: false,
+                    always_quote: true,
+                    show_control,
+                },
+                "shell-escape" => QuotingStyle::Shell {
+                    escape: true,
+                    always_quote: false,
+                    show_control,
+                },
+                "shell-escape-always" => QuotingStyle::Shell {
+                    escape: true,
+                    always_quote: true,
+                    show_control,
+                },
+                "c" => QuotingStyle::C {
+                    quotes: quoting_style::Quotes::Double,
+                },
+                "escape" => QuotingStyle::C {
+                    quotes: quoting_style::Quotes::None,
+                },
+                _ => unreachable!("Should have been caught by Clap"),
+            }
+        } else if options.is_present(options::quoting::LITERAL) {
+            QuotingStyle::Literal { show_control }
+        } else if options.is_present(options::quoting::ESCAPE) {
+            QuotingStyle::C {
+                quotes: quoting_style::Quotes::None,
+            }
+        } else if options.is_present(options::quoting::C) {
+            QuotingStyle::C {
+                quotes: quoting_style::Quotes::Double,
+            }
+        } else {
+            // TODO: use environment variable if available
+            QuotingStyle::Shell {
+                escape: true,
+                always_quote: false,
+                show_control,
+            }
+        };
+
+        let indicator_style = if let Some(field) = options.value_of(options::INDICATOR_STYLE) {
+            match field {
+                "none" => IndicatorStyle::None,
+                "file-type" => IndicatorStyle::FileType,
+                "classify" => IndicatorStyle::Classify,
+                "slash" => IndicatorStyle::Slash,
+                &_ => IndicatorStyle::None,
+            }
+        } else if options.is_present(options::indicator_style::CLASSIFY) {
+            IndicatorStyle::Classify
+        } else if options.is_present(options::indicator_style::SLASH) {
+            IndicatorStyle::Slash
+        } else if options.is_present(options::indicator_style::FILE_TYPE) {
+            IndicatorStyle::FileType
+        } else {
+            IndicatorStyle::None
+        };
+
+        let time_style = if let Some(field) = options.value_of(options::TIME_STYLE) {
+            //If both FULL_TIME and TIME_STYLE are present
+            //The one added last is dominant
+            if options.is_present(options::FULL_TIME)
+                && options.indices_of(options::FULL_TIME).unwrap().last()
+                    > options.indices_of(options::TIME_STYLE).unwrap().last()
+            {
+                TimeStyle::FullIso
+            } else {
+                //Clap handles the env variable "TIME_STYLE"
+                match field {
+                    "full-iso" => TimeStyle::FullIso,
+                    "long-iso" => TimeStyle::LongIso,
+                    "iso" => TimeStyle::Iso,
+                    "locale" => TimeStyle::Locale,
+                    // below should never happen as clap already restricts the values.
+                    _ => unreachable!("Invalid field for --time-style"),
+                }
+            }
+        } else if options.is_present(options::FULL_TIME) {
+            TimeStyle::FullIso
+        } else {
+            TimeStyle::Locale
+        };
+        let mut ignore_patterns = GlobSetBuilder::new();
+        if options.is_present(options::IGNORE_BACKUPS) {
+            ignore_patterns.add(Glob::new("*~").unwrap());
+            ignore_patterns.add(Glob::new(".*~").unwrap());
+        }
+
+        for pattern in options.values_of(options::IGNORE).into_iter().flatten() {
+            match Glob::new(pattern) {
+                Ok(p) => {
+                    ignore_patterns.add(p);
+                }
+                Err(_) => show_warning!("Invalid pattern for ignore: '{}'", pattern),
+            }
+        }
+
+        if files == Files::Normal {
+            for pattern in options.values_of(options::HIDE).into_iter().flatten() {
+                match Glob::new(pattern) {
+                    Ok(p) => {
+                        ignore_patterns.add(p);
+                    }
+                    Err(_) => show_warning!("Invalid pattern for hide: '{}'", pattern),
+                }
+            }
+        }
+
+        if files == Files::Normal {
+            ignore_patterns.add(Glob::new(".*").unwrap());
+        }
+
+        let ignore_patterns = ignore_patterns.build().unwrap();
+
+        let dereference = if options.is_present(options::dereference::ALL) {
+            Dereference::All
+        } else if options.is_present(options::dereference::ARGS) {
+            Dereference::Args
+        } else if options.is_present(options::dereference::DIR_ARGS) {
+            Dereference::DirArgs
+        } else if options.is_present(options::DIRECTORY)
+            || indicator_style == IndicatorStyle::Classify
+            || format == Format::Long
+        {
+            Dereference::None
+        } else {
+            Dereference::DirArgs
+        };
+
+        Ok(Config {
+            format,
+            files,
+            sort,
+            recursive: options.is_present(options::RECURSIVE),
+            reverse: options.is_present(options::REVERSE),
+            dereference,
+            ignore_patterns,
+            size_format,
+            directory: options.is_present(options::DIRECTORY),
+            time,
+            color,
+            #[cfg(unix)]
+            inode: options.is_present(options::INODE),
+            long,
+            width,
+            quoting_style,
+            indicator_style,
+            time_style,
+        })
+    }
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+
+    let app = uu_app().usage(&usage[..]);
+
+    let matches = app.get_matches_from(args);
+
+    let locs = matches
+        .values_of(options::PATHS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_else(|| vec![String::from(".")]);
+
+    list(locs, Config::from(matches)?)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(
+            "By default, ls will list the files and contents of any directories on \
+            the command line, expect that it will ignore files and directories \
+            whose names start with '.'.",
+        )
+        // Format arguments
+        .arg(
+            Arg::with_name(options::FORMAT)
+                .long(options::FORMAT)
+                .help("Set the display format.")
+                .takes_value(true)
+                .possible_values(&[
+                    "long",
+                    "verbose",
+                    "single-column",
+                    "columns",
+                    "vertical",
+                    "across",
+                    "horizontal",
+                    "commas",
+                ])
+                .hide_possible_values(true)
+                .require_equals(true)
+                .overrides_with_all(&[
+                    options::FORMAT,
+                    options::format::COLUMNS,
+                    options::format::LONG,
+                    options::format::ACROSS,
+                    options::format::COLUMNS,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::format::COLUMNS)
+                .short(options::format::COLUMNS)
+                .help("Display the files in columns.")
+                .overrides_with_all(&[
+                    options::FORMAT,
+                    options::format::COLUMNS,
+                    options::format::LONG,
+                    options::format::ACROSS,
+                    options::format::COLUMNS,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::format::LONG)
+                .short("l")
+                .long(options::format::LONG)
+                .help("Display detailed information.")
+                .overrides_with_all(&[
+                    options::FORMAT,
+                    options::format::COLUMNS,
+                    options::format::LONG,
+                    options::format::ACROSS,
+                    options::format::COLUMNS,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::format::ACROSS)
+                .short(options::format::ACROSS)
+                .help("List entries in rows instead of in columns.")
+                .overrides_with_all(&[
+                    options::FORMAT,
+                    options::format::COLUMNS,
+                    options::format::LONG,
+                    options::format::ACROSS,
+                    options::format::COLUMNS,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::format::COMMAS)
+                .short(options::format::COMMAS)
+                .help("List entries separated by commas.")
+                .overrides_with_all(&[
+                    options::FORMAT,
+                    options::format::COLUMNS,
+                    options::format::LONG,
+                    options::format::ACROSS,
+                    options::format::COLUMNS,
+                ]),
+        )
+        // The next four arguments do not override with the other format
+        // options, see the comment in Config::from for the reason.
+        // Ideally, they would use Arg::override_with, with their own name
+        // but that doesn't seem to work in all cases. Example:
+        // ls -1g1
+        // even though `ls -11` and `ls -1 -g -1` work.
+        .arg(
+            Arg::with_name(options::format::ONE_LINE)
+                .short(options::format::ONE_LINE)
+                .help("List one file per line.")
+                .multiple(true),
+        )
+        .arg(
+            Arg::with_name(options::format::LONG_NO_GROUP)
+                .short(options::format::LONG_NO_GROUP)
+                .help(
+                    "Long format without group information. \
+                    Identical to --format=long with --no-group.",
+                )
+                .multiple(true),
+        )
+        .arg(
+            Arg::with_name(options::format::LONG_NO_OWNER)
+                .short(options::format::LONG_NO_OWNER)
+                .help("Long format without owner information.")
+                .multiple(true),
+        )
+        .arg(
+            Arg::with_name(options::format::LONG_NUMERIC_UID_GID)
+                .short("n")
+                .long(options::format::LONG_NUMERIC_UID_GID)
+                .help("-l with numeric UIDs and GIDs.")
+                .multiple(true),
+        )
+        // Quoting style
+        .arg(
+            Arg::with_name(options::QUOTING_STYLE)
+                .long(options::QUOTING_STYLE)
+                .takes_value(true)
+                .help("Set quoting style.")
+                .possible_values(&[
+                    "literal",
+                    "shell",
+                    "shell-always",
+                    "shell-escape",
+                    "shell-escape-always",
+                    "c",
+                    "escape",
+                ])
+                .overrides_with_all(&[
+                    options::QUOTING_STYLE,
+                    options::quoting::LITERAL,
+                    options::quoting::ESCAPE,
+                    options::quoting::C,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::quoting::LITERAL)
+                .short("N")
+                .long(options::quoting::LITERAL)
+                .help("Use literal quoting style. Equivalent to `--quoting-style=literal`")
+                .overrides_with_all(&[
+                    options::QUOTING_STYLE,
+                    options::quoting::LITERAL,
+                    options::quoting::ESCAPE,
+                    options::quoting::C,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::quoting::ESCAPE)
+                .short("b")
+                .long(options::quoting::ESCAPE)
+                .help("Use escape quoting style. Equivalent to `--quoting-style=escape`")
+                .overrides_with_all(&[
+                    options::QUOTING_STYLE,
+                    options::quoting::LITERAL,
+                    options::quoting::ESCAPE,
+                    options::quoting::C,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::quoting::C)
+                .short("Q")
+                .long(options::quoting::C)
+                .help("Use C quoting style. Equivalent to `--quoting-style=c`")
+                .overrides_with_all(&[
+                    options::QUOTING_STYLE,
+                    options::quoting::LITERAL,
+                    options::quoting::ESCAPE,
+                    options::quoting::C,
+                ]),
+        )
+        // Control characters
+        .arg(
+            Arg::with_name(options::HIDE_CONTROL_CHARS)
+                .short("q")
+                .long(options::HIDE_CONTROL_CHARS)
+                .help("Replace control characters with '?' if they are not escaped.")
+                .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]),
+        )
+        .arg(
+            Arg::with_name(options::SHOW_CONTROL_CHARS)
+                .long(options::SHOW_CONTROL_CHARS)
+                .help("Show control characters 'as is' if they are not escaped.")
+                .overrides_with_all(&[options::HIDE_CONTROL_CHARS, options::SHOW_CONTROL_CHARS]),
+        )
+        // Time arguments
+        .arg(
+            Arg::with_name(options::TIME)
+                .long(options::TIME)
+                .help(
+                    "Show time in <field>:\n\
+                    \taccess time (-u): atime, access, use;\n\
+                    \tchange time (-t): ctime, status.\n\
+                    \tbirth time: birth, creation;",
+                )
+                .value_name("field")
+                .takes_value(true)
+                .possible_values(&[
+                    "atime", "access", "use", "ctime", "status", "birth", "creation",
+                ])
+                .hide_possible_values(true)
+                .require_equals(true)
+                .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]),
+        )
+        .arg(
+            Arg::with_name(options::time::CHANGE)
+                .short(options::time::CHANGE)
+                .help(
+                    "If the long listing format (e.g., -l, -o) is being used, print the status \
+                change time (the 'ctime' in the inode) instead of the modification time. When \
+                explicitly sorting by time (--sort=time or -t) or when not using a long listing \
+                format, sort according to the status change time.",
+                )
+                .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]),
+        )
+        .arg(
+            Arg::with_name(options::time::ACCESS)
+                .short(options::time::ACCESS)
+                .help(
+                    "If the long listing format (e.g., -l, -o) is being used, print the status \
+                access time instead of the modification time. When explicitly sorting by time \
+                (--sort=time or -t) or when not using a long listing format, sort according to the \
+                access time.",
+                )
+                .overrides_with_all(&[options::TIME, options::time::ACCESS, options::time::CHANGE]),
+        )
+        // Hide and ignore
+        .arg(
+            Arg::with_name(options::HIDE)
+                .long(options::HIDE)
+                .takes_value(true)
+                .multiple(true)
+                .value_name("PATTERN")
+                .help(
+                    "do not list implied entries matching shell PATTERN (overridden by -a or -A)",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE)
+                .short("I")
+                .long(options::IGNORE)
+                .takes_value(true)
+                .multiple(true)
+                .value_name("PATTERN")
+                .help("do not list implied entries matching shell PATTERN"),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_BACKUPS)
+                .short("B")
+                .long(options::IGNORE_BACKUPS)
+                .help("Ignore entries which end with ~."),
+        )
+        // Sort arguments
+        .arg(
+            Arg::with_name(options::SORT)
+                .long(options::SORT)
+                .help("Sort by <field>: name, none (-U), time (-t), size (-S) or extension (-X)")
+                .value_name("field")
+                .takes_value(true)
+                .possible_values(&["name", "none", "time", "size", "version", "extension"])
+                .require_equals(true)
+                .overrides_with_all(&[
+                    options::SORT,
+                    options::sort::SIZE,
+                    options::sort::TIME,
+                    options::sort::NONE,
+                    options::sort::VERSION,
+                    options::sort::EXTENSION,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::sort::SIZE)
+                .short(options::sort::SIZE)
+                .help("Sort by file size, largest first.")
+                .overrides_with_all(&[
+                    options::SORT,
+                    options::sort::SIZE,
+                    options::sort::TIME,
+                    options::sort::NONE,
+                    options::sort::VERSION,
+                    options::sort::EXTENSION,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::sort::TIME)
+                .short(options::sort::TIME)
+                .help("Sort by modification time (the 'mtime' in the inode), newest first.")
+                .overrides_with_all(&[
+                    options::SORT,
+                    options::sort::SIZE,
+                    options::sort::TIME,
+                    options::sort::NONE,
+                    options::sort::VERSION,
+                    options::sort::EXTENSION,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::sort::VERSION)
+                .short(options::sort::VERSION)
+                .help("Natural sort of (version) numbers in the filenames.")
+                .overrides_with_all(&[
+                    options::SORT,
+                    options::sort::SIZE,
+                    options::sort::TIME,
+                    options::sort::NONE,
+                    options::sort::VERSION,
+                    options::sort::EXTENSION,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::sort::EXTENSION)
+                .short(options::sort::EXTENSION)
+                .help("Sort alphabetically by entry extension.")
+                .overrides_with_all(&[
+                    options::SORT,
+                    options::sort::SIZE,
+                    options::sort::TIME,
+                    options::sort::NONE,
+                    options::sort::VERSION,
+                    options::sort::EXTENSION,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::sort::NONE)
+                .short(options::sort::NONE)
+                .help(
+                    "Do not sort; list the files in whatever order they are stored in the \
+    directory.  This is especially useful when listing very large directories, \
+    since not doing any sorting can be noticeably faster.",
+                )
+                .overrides_with_all(&[
+                    options::SORT,
+                    options::sort::SIZE,
+                    options::sort::TIME,
+                    options::sort::NONE,
+                    options::sort::VERSION,
+                    options::sort::EXTENSION,
+                ]),
+        )
+        // Dereferencing
+        .arg(
+            Arg::with_name(options::dereference::ALL)
+                .short("L")
+                .long(options::dereference::ALL)
+                .help(
+                    "When showing file information for a symbolic link, show information for the \
+                file the link references rather than the link itself.",
+                )
+                .overrides_with_all(&[
+                    options::dereference::ALL,
+                    options::dereference::DIR_ARGS,
+                    options::dereference::ARGS,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::dereference::DIR_ARGS)
+                .long(options::dereference::DIR_ARGS)
+                .help(
+                    "Do not dereference symlinks except when they link to directories and are \
+                given as command line arguments.",
+                )
+                .overrides_with_all(&[
+                    options::dereference::ALL,
+                    options::dereference::DIR_ARGS,
+                    options::dereference::ARGS,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::dereference::ARGS)
+                .short("H")
+                .long(options::dereference::ARGS)
+                .help("Do not dereference symlinks except when given as command line arguments.")
+                .overrides_with_all(&[
+                    options::dereference::ALL,
+                    options::dereference::DIR_ARGS,
+                    options::dereference::ARGS,
+                ]),
+        )
+        // Long format options
+        .arg(
+            Arg::with_name(options::NO_GROUP)
+                .long(options::NO_GROUP)
+                .short("-G")
+                .help("Do not show group in long format."),
+        )
+        .arg(Arg::with_name(options::AUTHOR).long(options::AUTHOR).help(
+            "Show author in long format. \
+            On the supported platforms, the author always matches the file owner.",
+        ))
+        // Other Flags
+        .arg(
+            Arg::with_name(options::files::ALL)
+                .short("a")
+                .long(options::files::ALL)
+                .help("Do not ignore hidden files (files with names that start with '.')."),
+        )
+        .arg(
+            Arg::with_name(options::files::ALMOST_ALL)
+                .short("A")
+                .long(options::files::ALMOST_ALL)
+                .help(
+                    "In a directory, do not ignore all file names that start with '.', \
+only ignore '.' and '..'.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::DIRECTORY)
+                .short("d")
+                .long(options::DIRECTORY)
+                .help(
+                    "Only list the names of directories, rather than listing directory contents. \
+                This will not follow symbolic links unless one of `--dereference-command-line \
+                (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is \
+                specified.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::size::HUMAN_READABLE)
+                .short("h")
+                .long(options::size::HUMAN_READABLE)
+                .help("Print human readable file sizes (e.g. 1K 234M 56G).")
+                .overrides_with(options::size::SI),
+        )
+        .arg(
+            Arg::with_name(options::size::SI)
+                .long(options::size::SI)
+                .help("Print human readable file sizes using powers of 1000 instead of 1024."),
+        )
+        .arg(
+            Arg::with_name(options::INODE)
+                .short("i")
+                .long(options::INODE)
+                .help("print the index number of each file"),
+        )
+        .arg(
+            Arg::with_name(options::REVERSE)
+                .short("r")
+                .long(options::REVERSE)
+                .help(
+                    "Reverse whatever the sorting method is e.g., list files in reverse \
+                alphabetical order, youngest first, smallest first, or whatever.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::RECURSIVE)
+                .short("R")
+                .long(options::RECURSIVE)
+                .help("List the contents of all directories recursively."),
+        )
+        .arg(
+            Arg::with_name(options::WIDTH)
+                .long(options::WIDTH)
+                .short("w")
+                .help("Assume that the terminal is COLS columns wide.")
+                .value_name("COLS")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::COLOR)
+                .long(options::COLOR)
+                .help("Color output based on file type.")
+                .takes_value(true)
+                .require_equals(true)
+                .min_values(0),
+        )
+        .arg(
+            Arg::with_name(options::INDICATOR_STYLE)
+                .long(options::INDICATOR_STYLE)
+                .help(
+                    "Append indicator with style WORD to entry names: \
+                    none (default),  slash (-p), file-type (--file-type), classify (-F)",
+                )
+                .takes_value(true)
+                .possible_values(&["none", "slash", "file-type", "classify"])
+                .overrides_with_all(&[
+                    options::indicator_style::FILE_TYPE,
+                    options::indicator_style::SLASH,
+                    options::indicator_style::CLASSIFY,
+                    options::INDICATOR_STYLE,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::indicator_style::CLASSIFY)
+                .short("F")
+                .long(options::indicator_style::CLASSIFY)
+                .help(
+                    "Append a character to each file name indicating the file type. Also, for \
+                regular files that are executable, append '*'. The file type indicators are \
+                '/' for directories, '@' for symbolic links, '|' for FIFOs, '=' for sockets, \
+                '>' for doors, and nothing for regular files.",
+                )
+                .overrides_with_all(&[
+                    options::indicator_style::FILE_TYPE,
+                    options::indicator_style::SLASH,
+                    options::indicator_style::CLASSIFY,
+                    options::INDICATOR_STYLE,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::indicator_style::FILE_TYPE)
+                .long(options::indicator_style::FILE_TYPE)
+                .help("Same as --classify, but do not append '*'")
+                .overrides_with_all(&[
+                    options::indicator_style::FILE_TYPE,
+                    options::indicator_style::SLASH,
+                    options::indicator_style::CLASSIFY,
+                    options::INDICATOR_STYLE,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::indicator_style::SLASH)
+                .short(options::indicator_style::SLASH)
+                .help("Append / indicator to directories.")
+                .overrides_with_all(&[
+                    options::indicator_style::FILE_TYPE,
+                    options::indicator_style::SLASH,
+                    options::indicator_style::CLASSIFY,
+                    options::INDICATOR_STYLE,
+                ]),
+        )
+        .arg(
+            //This still needs support for posix-*, +FORMAT
+            Arg::with_name(options::TIME_STYLE)
+                .long(options::TIME_STYLE)
+                .help("time/date format with -l; see TIME_STYLE below")
+                .value_name("TIME_STYLE")
+                .env("TIME_STYLE")
+                .possible_values(&["full-iso", "long-iso", "iso", "locale"])
+                .overrides_with_all(&[options::TIME_STYLE]),
+        )
+        .arg(
+            Arg::with_name(options::FULL_TIME)
+                .long(options::FULL_TIME)
+                .overrides_with(options::FULL_TIME)
+                .help("like -l --time-style=full-iso"),
+        )
+        // Positional arguments
+        .arg(
+            Arg::with_name(options::PATHS)
+                .multiple(true)
+                .takes_value(true),
+        )
+        .after_help(
+            "The TIME_STYLE argument can be full-iso, long-iso, iso. \
+            Also the TIME_STYLE environment variable sets the default style to use.",
+        )
+}
+
+/// Represents a Path along with it's associated data
+/// Any data that will be reused several times makes sense to be added to this structure
+/// Caching data here helps eliminate redundant syscalls to fetch same information
+struct PathData {
+    // Result<MetaData> got from symlink_metadata() or metadata() based on config
+    md: OnceCell<Option<Metadata>>,
+    ft: OnceCell<Option<FileType>>,
+    // Name of the file - will be empty for . or ..
+    display_name: String,
+    // PathBuf that all above data corresponds to
+    p_buf: PathBuf,
+    must_dereference: bool,
+}
+
+impl PathData {
+    fn new(
+        p_buf: PathBuf,
+        file_type: Option<std::io::Result<FileType>>,
+        file_name: Option<String>,
+        config: &Config,
+        command_line: bool,
+    ) -> Self {
+        // We cannot use `Path::ends_with` or `Path::Components`, because they remove occurrences of '.'
+        // For '..', the filename is None
+        let display_name = if let Some(name) = file_name {
+            name
+        } else {
+            let display_os_str = if command_line {
+                p_buf.as_os_str()
+            } else {
+                p_buf
+                    .file_name()
+                    .unwrap_or_else(|| p_buf.iter().next_back().unwrap())
+            };
+
+            display_os_str.to_string_lossy().into_owned()
+        };
+        let must_dereference = match &config.dereference {
+            Dereference::All => true,
+            Dereference::Args => command_line,
+            Dereference::DirArgs => {
+                if command_line {
+                    if let Ok(md) = p_buf.metadata() {
+                        md.is_dir()
+                    } else {
+                        false
+                    }
+                } else {
+                    false
+                }
+            }
+            Dereference::None => false,
+        };
+        let ft = match file_type {
+            Some(ft) => OnceCell::from(ft.ok()),
+            None => OnceCell::new(),
+        };
+
+        Self {
+            md: OnceCell::new(),
+            ft,
+            display_name,
+            p_buf,
+            must_dereference,
+        }
+    }
+
+    fn md(&self) -> Option<&Metadata> {
+        self.md
+            .get_or_init(|| get_metadata(&self.p_buf, self.must_dereference).ok())
+            .as_ref()
+    }
+
+    fn file_type(&self) -> Option<&FileType> {
+        self.ft
+            .get_or_init(|| self.md().map(|md| md.file_type()))
+            .as_ref()
+    }
+}
+
+fn list(locs: Vec<String>, config: Config) -> UResult<()> {
+    let mut files = Vec::<PathData>::new();
+    let mut dirs = Vec::<PathData>::new();
+
+    let mut out = BufWriter::new(stdout());
+
+    for loc in &locs {
+        let p = PathBuf::from(&loc);
+        let path_data = PathData::new(p, None, None, &config, true);
+
+        if path_data.md().is_none() {
+            show!(std::io::ErrorKind::NotFound
+                .map_err_context(|| format!("cannot access '{}'", path_data.p_buf.display())));
+            // We found an error, no need to continue the execution
+            continue;
+        }
+
+        let show_dir_contents = match path_data.file_type() {
+            Some(ft) => !config.directory && ft.is_dir(),
+            None => {
+                set_exit_code(1);
+                false
+            }
+        };
+
+        if show_dir_contents {
+            dirs.push(path_data);
+        } else {
+            files.push(path_data);
+        }
+    }
+    sort_entries(&mut files, &config);
+    display_items(&files, &config, &mut out);
+
+    sort_entries(&mut dirs, &config);
+    for dir in dirs {
+        if locs.len() > 1 || config.recursive {
+            let _ = writeln!(out, "\n{}:", dir.p_buf.display());
+        }
+        enter_directory(&dir, &config, &mut out);
+    }
+
+    Ok(())
+}
+
+fn sort_entries(entries: &mut Vec<PathData>, config: &Config) {
+    match config.sort {
+        Sort::Time => entries.sort_by_key(|k| {
+            Reverse(
+                k.md()
+                    .and_then(|md| get_system_time(md, config))
+                    .unwrap_or(UNIX_EPOCH),
+            )
+        }),
+        Sort::Size => {
+            entries.sort_by_key(|k| Reverse(k.md().as_ref().map(|md| md.len()).unwrap_or(0)))
+        }
+        // The default sort in GNU ls is case insensitive
+        Sort::Name => entries.sort_by(|a, b| a.display_name.cmp(&b.display_name)),
+        Sort::Version => entries
+            .sort_by(|a, b| version_cmp(&a.p_buf.to_string_lossy(), &b.p_buf.to_string_lossy())),
+        Sort::Extension => entries.sort_by(|a, b| {
+            a.p_buf
+                .extension()
+                .cmp(&b.p_buf.extension())
+                .then(a.p_buf.file_stem().cmp(&b.p_buf.file_stem()))
+        }),
+        Sort::None => {}
+    }
+
+    if config.reverse {
+        entries.reverse();
+    }
+}
+
+#[cfg(windows)]
+fn is_hidden(file_path: &DirEntry) -> bool {
+    let path = file_path.path();
+    let metadata = fs::metadata(&path).unwrap_or_else(|_| fs::symlink_metadata(&path).unwrap());
+    let attr = metadata.file_attributes();
+    (attr & 0x2) > 0
+}
+
+fn should_display(entry: &DirEntry, config: &Config) -> bool {
+    let ffi_name = entry.file_name();
+
+    // For unix, the hidden files are already included in the ignore pattern
+    #[cfg(windows)]
+    {
+        if config.files == Files::Normal && is_hidden(entry) {
+            return false;
+        }
+    }
+
+    !config.ignore_patterns.is_match(&ffi_name)
+}
+
+fn enter_directory(dir: &PathData, config: &Config, out: &mut BufWriter<Stdout>) {
+    let mut entries: Vec<_> = if config.files == Files::All {
+        vec![
+            PathData::new(
+                dir.p_buf.clone(),
+                Some(Ok(*dir.file_type().unwrap())),
+                Some(".".into()),
+                config,
+                false,
+            ),
+            PathData::new(dir.p_buf.join(".."), None, Some("..".into()), config, false),
+        ]
+    } else {
+        vec![]
+    };
+
+    let mut temp: Vec<_> = safe_unwrap!(fs::read_dir(&dir.p_buf))
+        .map(|res| safe_unwrap!(res))
+        .filter(|e| should_display(e, config))
+        .map(|e| PathData::new(DirEntry::path(&e), Some(e.file_type()), None, config, false))
+        .collect();
+
+    sort_entries(&mut temp, config);
+
+    entries.append(&mut temp);
+
+    display_items(&entries, config, out);
+
+    if config.recursive {
+        for e in entries
+            .iter()
+            .skip(if config.files == Files::All { 2 } else { 0 })
+            .filter(|p| p.file_type().map(|ft| ft.is_dir()).unwrap_or(false))
+        {
+            let _ = writeln!(out, "\n{}:", e.p_buf.display());
+            enter_directory(e, config, out);
+        }
+    }
+}
+
+fn get_metadata(entry: &Path, dereference: bool) -> std::io::Result<Metadata> {
+    if dereference {
+        entry.metadata()
+    } else {
+        entry.symlink_metadata()
+    }
+}
+
+fn display_dir_entry_size(entry: &PathData, config: &Config) -> (usize, usize) {
+    if let Some(md) = entry.md() {
+        (
+            display_symlink_count(md).len(),
+            display_size_or_rdev(md, config).len(),
+        )
+    } else {
+        (0, 0)
+    }
+}
+
+fn pad_left(string: String, count: usize) -> String {
+    format!("{:>width$}", string, width = count)
+}
+
+fn display_items(items: &[PathData], config: &Config, out: &mut BufWriter<Stdout>) {
+    if config.format == Format::Long {
+        let (mut max_links, mut max_width) = (1, 1);
+        let mut total_size = 0;
+
+        for item in items {
+            let (links, width) = display_dir_entry_size(item, config);
+            max_links = links.max(max_links);
+            max_width = width.max(max_width);
+            total_size += item.md().map_or(0, |md| get_block_size(md, config));
+        }
+
+        if total_size > 0 {
+            let _ = writeln!(out, "total {}", display_size(total_size, config));
+        }
+
+        for item in items {
+            display_item_long(item, max_links, max_width, config, out);
+        }
+    } else {
+        let names = items.iter().filter_map(|i| display_file_name(i, config));
+
+        match config.format {
+            Format::Columns => display_grid(names, config.width, Direction::TopToBottom, out),
+            Format::Across => display_grid(names, config.width, Direction::LeftToRight, out),
+            Format::Commas => {
+                let mut current_col = 0;
+                let mut names = names;
+                if let Some(name) = names.next() {
+                    let _ = write!(out, "{}", name.contents);
+                    current_col = name.width as u16 + 2;
+                }
+                for name in names {
+                    let name_width = name.width as u16;
+                    // If the width is 0 we print one single line
+                    if config.width != 0 && current_col + name_width + 1 > config.width {
+                        current_col = name_width + 2;
+                        let _ = write!(out, ",\n{}", name.contents);
+                    } else {
+                        current_col += name_width + 2;
+                        let _ = write!(out, ", {}", name.contents);
+                    }
+                }
+                // Current col is never zero again if names have been printed.
+                // So we print a newline.
+                if current_col > 0 {
+                    let _ = writeln!(out,);
+                }
+            }
+            _ => {
+                for name in names {
+                    let _ = writeln!(out, "{}", name.contents);
+                }
+            }
+        }
+    }
+}
+
+fn get_block_size(md: &Metadata, config: &Config) -> u64 {
+    /* GNU ls will display sizes in terms of block size
+       md.len() will differ from this value when the file has some holes
+    */
+    #[cfg(unix)]
+    {
+        // hard-coded for now - enabling setting this remains a TODO
+        let ls_block_size = 1024;
+        match config.size_format {
+            SizeFormat::Binary => md.blocks() * 512,
+            SizeFormat::Decimal => md.blocks() * 512,
+            SizeFormat::Bytes => md.blocks() * 512 / ls_block_size,
+        }
+    }
+
+    #[cfg(not(unix))]
+    {
+        let _ = config;
+        // no way to get block size for windows, fall-back to file size
+        md.len()
+    }
+}
+
+fn display_grid(
+    names: impl Iterator<Item = Cell>,
+    width: u16,
+    direction: Direction,
+    out: &mut BufWriter<Stdout>,
+) {
+    if width == 0 {
+        // If the width is 0 we print one single line
+        let mut printed_something = false;
+        for name in names {
+            if printed_something {
+                let _ = write!(out, "  ");
+            }
+            printed_something = true;
+            let _ = write!(out, "{}", name.contents);
+        }
+        if printed_something {
+            let _ = writeln!(out);
+        }
+    } else {
+        let mut grid = Grid::new(GridOptions {
+            filling: Filling::Spaces(2),
+            direction,
+        });
+
+        for name in names {
+            grid.add(name);
+        }
+
+        match grid.fit_into_width(width as usize) {
+            Some(output) => {
+                let _ = write!(out, "{}", output);
+            }
+            // Width is too small for the grid, so we fit it in one column
+            None => {
+                let _ = write!(out, "{}", grid.fit_into_columns(1));
+            }
+        }
+    }
+}
+
+fn display_item_long(
+    item: &PathData,
+    max_links: usize,
+    max_size: usize,
+    config: &Config,
+    out: &mut BufWriter<Stdout>,
+) {
+    let md = match item.md() {
+        None => {
+            show!(LsError::NoMetadata(item.p_buf.clone()));
+            return;
+        }
+        Some(md) => md,
+    };
+
+    #[cfg(unix)]
+    {
+        if config.inode {
+            let _ = write!(out, "{} ", get_inode(md));
+        }
+    }
+
+    let _ = write!(
+        out,
+        "{} {}",
+        display_permissions(md, true),
+        pad_left(display_symlink_count(md), max_links),
+    );
+
+    if config.long.owner {
+        let _ = write!(out, " {}", display_uname(md, config));
+    }
+
+    if config.long.group {
+        let _ = write!(out, " {}", display_group(md, config));
+    }
+
+    // Author is only different from owner on GNU/Hurd, so we reuse
+    // the owner, since GNU/Hurd is not currently supported by Rust.
+    if config.long.author {
+        let _ = write!(out, " {}", display_uname(md, config));
+    }
+
+    let _ = writeln!(
+        out,
+        " {} {} {}",
+        pad_left(display_size_or_rdev(md, config), max_size),
+        display_date(md, config),
+        // unwrap is fine because it fails when metadata is not available
+        // but we already know that it is because it's checked at the
+        // start of the function.
+        display_file_name(item, config).unwrap().contents,
+    );
+}
+
+#[cfg(unix)]
+fn get_inode(metadata: &Metadata) -> String {
+    format!("{:8}", metadata.ino())
+}
+
+// Currently getpwuid is `linux` target only. If it's broken out into
+// a posix-compliant attribute this can be updated...
+#[cfg(unix)]
+use std::sync::Mutex;
+#[cfg(unix)]
+use uucore::entries;
+use uucore::InvalidEncodingHandling;
+
+#[cfg(unix)]
+fn cached_uid2usr(uid: u32) -> String {
+    lazy_static! {
+        static ref UID_CACHE: Mutex<HashMap<u32, String>> = Mutex::new(HashMap::new());
+    }
+
+    let mut uid_cache = UID_CACHE.lock().unwrap();
+    uid_cache
+        .entry(uid)
+        .or_insert_with(|| entries::uid2usr(uid).unwrap_or_else(|_| uid.to_string()))
+        .clone()
+}
+
+#[cfg(unix)]
+fn display_uname(metadata: &Metadata, config: &Config) -> String {
+    if config.long.numeric_uid_gid {
+        metadata.uid().to_string()
+    } else {
+        cached_uid2usr(metadata.uid())
+    }
+}
+
+#[cfg(all(unix, not(target_os = "redox")))]
+fn cached_gid2grp(gid: u32) -> String {
+    lazy_static! {
+        static ref GID_CACHE: Mutex<HashMap<u32, String>> = Mutex::new(HashMap::new());
+    }
+
+    let mut gid_cache = GID_CACHE.lock().unwrap();
+    gid_cache
+        .entry(gid)
+        .or_insert_with(|| entries::gid2grp(gid).unwrap_or_else(|_| gid.to_string()))
+        .clone()
+}
+
+#[cfg(all(unix, not(target_os = "redox")))]
+fn display_group(metadata: &Metadata, config: &Config) -> String {
+    if config.long.numeric_uid_gid {
+        metadata.gid().to_string()
+    } else {
+        cached_gid2grp(metadata.gid())
+    }
+}
+
+#[cfg(target_os = "redox")]
+fn display_group(metadata: &Metadata, config: &Config) -> String {
+    metadata.gid().to_string()
+}
+
+#[cfg(not(unix))]
+fn display_uname(_metadata: &Metadata, _config: &Config) -> String {
+    "somebody".to_string()
+}
+
+#[cfg(not(unix))]
+fn display_group(_metadata: &Metadata, _config: &Config) -> String {
+    "somegroup".to_string()
+}
+
+// The implementations for get_time are separated because some options, such
+// as ctime will not be available
+#[cfg(unix)]
+fn get_system_time(md: &Metadata, config: &Config) -> Option<SystemTime> {
+    match config.time {
+        Time::Change => Some(UNIX_EPOCH + Duration::new(md.ctime() as u64, md.ctime_nsec() as u32)),
+        Time::Modification => md.modified().ok(),
+        Time::Access => md.accessed().ok(),
+        Time::Birth => md.created().ok(),
+    }
+}
+
+#[cfg(not(unix))]
+fn get_system_time(md: &Metadata, config: &Config) -> Option<SystemTime> {
+    match config.time {
+        Time::Modification => md.modified().ok(),
+        Time::Access => md.accessed().ok(),
+        Time::Birth => md.created().ok(),
+        _ => None,
+    }
+}
+
+fn get_time(md: &Metadata, config: &Config) -> Option<chrono::DateTime<chrono::Local>> {
+    let time = get_system_time(md, config)?;
+    Some(time.into())
+}
+
+fn display_date(metadata: &Metadata, config: &Config) -> String {
+    match get_time(metadata, config) {
+        Some(time) => {
+            //Date is recent if from past 6 months
+            //According to GNU a Gregorian year has 365.2425 * 24 * 60 * 60 == 31556952 seconds on the average.
+            let recent = time + chrono::Duration::seconds(31_556_952 / 2) > chrono::Local::now();
+
+            match config.time_style {
+                TimeStyle::FullIso => time.format("%Y-%m-%d %H:%M:%S.%f %z"),
+                TimeStyle::LongIso => time.format("%Y-%m-%d %H:%M"),
+                TimeStyle::Iso => time.format(if recent { "%m-%d %H:%M" } else { "%Y-%m-%d " }),
+                TimeStyle::Locale => {
+                    let fmt = if recent { "%b %e %H:%M" } else { "%b %e  %Y" };
+
+                    // spell-checker:ignore (word) datetime
+                    //In this version of chrono translating can be done
+                    //The function is chrono::datetime::DateTime::format_localized
+                    //However it's currently still hard to get the current pure-rust-locale
+                    //So it's not yet implemented
+
+                    time.format(fmt)
+                }
+            }
+            .to_string()
+        }
+        None => "???".into(),
+    }
+}
+
+// There are a few peculiarities to how GNU formats the sizes:
+// 1. One decimal place is given if and only if the size is smaller than 10
+// 2. It rounds sizes up.
+// 3. The human-readable format uses powers for 1024, but does not display the "i"
+//    that is commonly used to denote Kibi, Mebi, etc.
+// 4. Kibi and Kilo are denoted differently ("k" and "K", respectively)
+fn format_prefixed(prefixed: NumberPrefix<f64>) -> String {
+    match prefixed {
+        NumberPrefix::Standalone(bytes) => bytes.to_string(),
+        NumberPrefix::Prefixed(prefix, bytes) => {
+            // Remove the "i" from "Ki", "Mi", etc. if present
+            let prefix_str = prefix.symbol().trim_end_matches('i');
+
+            // Check whether we get more than 10 if we round up to the first decimal
+            // because we want do display 9.81 as "9.9", not as "10".
+            if (10.0 * bytes).ceil() >= 100.0 {
+                format!("{:.0}{}", bytes.ceil(), prefix_str)
+            } else {
+                format!("{:.1}{}", (10.0 * bytes).ceil() / 10.0, prefix_str)
+            }
+        }
+    }
+}
+
+fn display_size_or_rdev(metadata: &Metadata, config: &Config) -> String {
+    #[cfg(unix)]
+    {
+        let ft = metadata.file_type();
+        if ft.is_char_device() || ft.is_block_device() {
+            let dev: u64 = metadata.rdev();
+            let major = (dev >> 8) as u8;
+            let minor = dev as u8;
+            return format!("{}, {}", major, minor);
+        }
+    }
+
+    display_size(metadata.len(), config)
+}
+
+fn display_size(size: u64, config: &Config) -> String {
+    // NOTE: The human-readable behavior deviates from the GNU ls.
+    // The GNU ls uses binary prefixes by default.
+    match config.size_format {
+        SizeFormat::Binary => format_prefixed(NumberPrefix::binary(size as f64)),
+        SizeFormat::Decimal => format_prefixed(NumberPrefix::decimal(size as f64)),
+        SizeFormat::Bytes => size.to_string(),
+    }
+}
+
+#[cfg(unix)]
+fn file_is_executable(md: &Metadata) -> bool {
+    // Mode always returns u32, but the flags might not be, based on the platform
+    // e.g. linux has u32, mac has u16.
+    // S_IXUSR -> user has execute permission
+    // S_IXGRP -> group has execute permission
+    // S_IXOTH -> other users have execute permission
+    md.mode() & ((S_IXUSR | S_IXGRP | S_IXOTH) as u32) != 0
+}
+
+fn classify_file(path: &PathData) -> Option<char> {
+    let file_type = path.file_type()?;
+
+    if file_type.is_dir() {
+        Some('/')
+    } else if file_type.is_symlink() {
+        Some('@')
+    } else {
+        #[cfg(unix)]
+        {
+            if file_type.is_socket() {
+                Some('=')
+            } else if file_type.is_fifo() {
+                Some('|')
+            } else if file_type.is_file() && file_is_executable(path.md()?) {
+                Some('*')
+            } else {
+                None
+            }
+        }
+        #[cfg(not(unix))]
+        None
+    }
+}
+
+fn display_file_name(path: &PathData, config: &Config) -> Option<Cell> {
+    let mut name = escape_name(&path.display_name, &config.quoting_style);
+
+    #[cfg(unix)]
+    {
+        if config.format != Format::Long && config.inode {
+            name = path
+                .md()
+                .map_or_else(|| "?".to_string(), |md| get_inode(md))
+                + " "
+                + &name;
+        }
+    }
+
+    // We need to keep track of the width ourselves instead of letting term_grid
+    // infer it because the color codes mess up term_grid's width calculation.
+    let mut width = name.width();
+
+    if let Some(ls_colors) = &config.color {
+        name = color_name(ls_colors, &path.p_buf, name, path.md()?);
+    }
+
+    if config.indicator_style != IndicatorStyle::None {
+        let sym = classify_file(path);
+
+        let char_opt = match config.indicator_style {
+            IndicatorStyle::Classify => sym,
+            IndicatorStyle::FileType => {
+                // Don't append an asterisk.
+                match sym {
+                    Some('*') => None,
+                    _ => sym,
+                }
+            }
+            IndicatorStyle::Slash => {
+                // Append only a slash.
+                match sym {
+                    Some('/') => Some('/'),
+                    _ => None,
+                }
+            }
+            IndicatorStyle::None => None,
+        };
+
+        if let Some(c) = char_opt {
+            name.push(c);
+            width += 1;
+        }
+    }
+
+    if config.format == Format::Long && path.file_type()?.is_symlink() {
+        if let Ok(target) = path.p_buf.read_link() {
+            name.push_str(" -> ");
+            name.push_str(&target.to_string_lossy());
+        }
+    }
+
+    Some(Cell {
+        contents: name,
+        width,
+    })
+}
+
+fn color_name(ls_colors: &LsColors, path: &Path, name: String, md: &Metadata) -> String {
+    match ls_colors.style_for_path_with_metadata(path, Some(md)) {
+        Some(style) => style.to_ansi_term_style().paint(name).to_string(),
+        None => name,
+    }
+}
+
+#[cfg(not(unix))]
+fn display_symlink_count(_metadata: &Metadata) -> String {
+    // Currently not sure of how to get this on Windows, so I'm punting.
+    // Git Bash looks like it may do the same thing.
+    String::from("1")
+}
+
+#[cfg(unix)]
+fn display_symlink_count(metadata: &Metadata) -> String {
+    metadata.nlink().to_string()
+}
+
+
\ No newline at end of file diff --git a/src/uu_ls/quoting_style.rs.html b/src/uu_ls/quoting_style.rs.html new file mode 100644 index 000000000..06c030b0e --- /dev/null +++ b/src/uu_ls/quoting_style.rs.html @@ -0,0 +1,1329 @@ +quoting_style.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+
+use std::char::from_digit;
+
+const SPECIAL_SHELL_CHARS: &str = "~`#$&*()|[]{};\\'\"<>?! ";
+
+pub(super) enum QuotingStyle {
+    Shell {
+        escape: bool,
+        always_quote: bool,
+        show_control: bool,
+    },
+    C {
+        quotes: Quotes,
+    },
+    Literal {
+        show_control: bool,
+    },
+}
+
+#[derive(Clone, Copy)]
+pub(super) enum Quotes {
+    None,
+    Single,
+    Double,
+    // TODO: Locale
+}
+
+// This implementation is heavily inspired by the std::char::EscapeDefault implementation
+// in the Rust standard library. This custom implementation is needed because the
+// characters \a, \b, \e, \f & \v are not recognized by Rust.
+struct EscapedChar {
+    state: EscapeState,
+}
+
+enum EscapeState {
+    Done,
+    Char(char),
+    Backslash(char),
+    ForceQuote(char),
+    Octal(EscapeOctal),
+}
+
+struct EscapeOctal {
+    c: char,
+    state: EscapeOctalState,
+    idx: usize,
+}
+
+enum EscapeOctalState {
+    Done,
+    Backslash,
+    Value,
+}
+
+impl Iterator for EscapeOctal {
+    type Item = char;
+
+    fn next(&mut self) -> Option<char> {
+        match self.state {
+            EscapeOctalState::Done => None,
+            EscapeOctalState::Backslash => {
+                self.state = EscapeOctalState::Value;
+                Some('\\')
+            }
+            EscapeOctalState::Value => {
+                let octal_digit = ((self.c as u32) >> (self.idx * 3)) & 0o7;
+                if self.idx == 0 {
+                    self.state = EscapeOctalState::Done;
+                } else {
+                    self.idx -= 1;
+                }
+                Some(from_digit(octal_digit, 8).unwrap())
+            }
+        }
+    }
+}
+
+impl EscapeOctal {
+    fn from(c: char) -> EscapeOctal {
+        EscapeOctal {
+            c,
+            idx: 2,
+            state: EscapeOctalState::Backslash,
+        }
+    }
+}
+
+impl EscapedChar {
+    fn new_literal(c: char) -> Self {
+        Self {
+            state: EscapeState::Char(c),
+        }
+    }
+
+    fn new_c(c: char, quotes: Quotes) -> Self {
+        use EscapeState::*;
+        let init_state = match c {
+            '\x07' => Backslash('a'),
+            '\x08' => Backslash('b'),
+            '\t' => Backslash('t'),
+            '\n' => Backslash('n'),
+            '\x0B' => Backslash('v'),
+            '\x0C' => Backslash('f'),
+            '\r' => Backslash('r'),
+            '\\' => Backslash('\\'),
+            '\'' => match quotes {
+                Quotes::Single => Backslash('\''),
+                _ => Char('\''),
+            },
+            '"' => match quotes {
+                Quotes::Double => Backslash('"'),
+                _ => Char('"'),
+            },
+            ' ' => match quotes {
+                Quotes::None => Backslash(' '),
+                _ => Char(' '),
+            },
+            _ if c.is_ascii_control() => Octal(EscapeOctal::from(c)),
+            _ => Char(c),
+        };
+        Self { state: init_state }
+    }
+
+    fn new_shell(c: char, escape: bool, quotes: Quotes) -> Self {
+        use EscapeState::*;
+        let init_state = match c {
+            _ if !escape && c.is_control() => Char(c),
+            '\x07' => Backslash('a'),
+            '\x08' => Backslash('b'),
+            '\t' => Backslash('t'),
+            '\n' => Backslash('n'),
+            '\x0B' => Backslash('v'),
+            '\x0C' => Backslash('f'),
+            '\r' => Backslash('r'),
+            '\x00'..='\x1F' | '\x7F' => Octal(EscapeOctal::from(c)),
+            '\'' => match quotes {
+                Quotes::Single => Backslash('\''),
+                _ => Char('\''),
+            },
+            _ if SPECIAL_SHELL_CHARS.contains(c) => ForceQuote(c),
+            _ => Char(c),
+        };
+        Self { state: init_state }
+    }
+
+    fn hide_control(self) -> Self {
+        match self.state {
+            EscapeState::Char(c) if c.is_control() => Self {
+                state: EscapeState::Char('?'),
+            },
+            _ => self,
+        }
+    }
+}
+
+impl Iterator for EscapedChar {
+    type Item = char;
+
+    fn next(&mut self) -> Option<char> {
+        match self.state {
+            EscapeState::Backslash(c) => {
+                self.state = EscapeState::Char(c);
+                Some('\\')
+            }
+            EscapeState::Char(c) | EscapeState::ForceQuote(c) => {
+                self.state = EscapeState::Done;
+                Some(c)
+            }
+            EscapeState::Done => None,
+            EscapeState::Octal(ref mut iter) => iter.next(),
+        }
+    }
+}
+
+fn shell_without_escape(name: &str, quotes: Quotes, show_control_chars: bool) -> (String, bool) {
+    let mut must_quote = false;
+    let mut escaped_str = String::with_capacity(name.len());
+
+    for c in name.chars() {
+        let escaped = {
+            let ec = EscapedChar::new_shell(c, false, quotes);
+            if show_control_chars {
+                ec
+            } else {
+                ec.hide_control()
+            }
+        };
+
+        match escaped.state {
+            EscapeState::Backslash('\'') => escaped_str.push_str("'\\''"),
+            EscapeState::ForceQuote(x) => {
+                must_quote = true;
+                escaped_str.push(x);
+            }
+            _ => {
+                for char in escaped {
+                    escaped_str.push(char);
+                }
+            }
+        }
+    }
+    (escaped_str, must_quote)
+}
+
+fn shell_with_escape(name: &str, quotes: Quotes) -> (String, bool) {
+    // We need to keep track of whether we are in a dollar expression
+    // because e.g. \b\n is escaped as $'\b\n' and not like $'b'$'n'
+    let mut in_dollar = false;
+    let mut must_quote = false;
+    let mut escaped_str = String::with_capacity(name.len());
+
+    for c in name.chars() {
+        let escaped = EscapedChar::new_shell(c, true, quotes);
+        match escaped.state {
+            EscapeState::Char(x) => {
+                if in_dollar {
+                    escaped_str.push_str("''");
+                    in_dollar = false;
+                }
+                escaped_str.push(x);
+            }
+            EscapeState::ForceQuote(x) => {
+                if in_dollar {
+                    escaped_str.push_str("''");
+                    in_dollar = false;
+                }
+                must_quote = true;
+                escaped_str.push(x);
+            }
+            // Single quotes are not put in dollar expressions, but are escaped
+            // if the string also contains double quotes. In that case, they must
+            // be handled separately.
+            EscapeState::Backslash('\'') => {
+                must_quote = true;
+                in_dollar = false;
+                escaped_str.push_str("'\\''");
+            }
+            _ => {
+                if !in_dollar {
+                    escaped_str.push_str("'$'");
+                    in_dollar = true;
+                }
+                must_quote = true;
+                for char in escaped {
+                    escaped_str.push(char);
+                }
+            }
+        }
+    }
+    (escaped_str, must_quote)
+}
+
+pub(super) fn escape_name(name: &str, style: &QuotingStyle) -> String {
+    match style {
+        QuotingStyle::Literal { show_control } => {
+            if !show_control {
+                name.chars()
+                    .flat_map(|c| EscapedChar::new_literal(c).hide_control())
+                    .collect()
+            } else {
+                name.into()
+            }
+        }
+        QuotingStyle::C { quotes } => {
+            let escaped_str: String = name
+                .chars()
+                .flat_map(|c| EscapedChar::new_c(c, *quotes))
+                .collect();
+
+            match quotes {
+                Quotes::Single => format!("'{}'", escaped_str),
+                Quotes::Double => format!("\"{}\"", escaped_str),
+                _ => escaped_str,
+            }
+        }
+        QuotingStyle::Shell {
+            escape,
+            always_quote,
+            show_control,
+        } => {
+            let (quotes, must_quote) = if name.contains('"') {
+                (Quotes::Single, true)
+            } else if name.contains('\'') {
+                (Quotes::Double, true)
+            } else if *always_quote {
+                (Quotes::Single, true)
+            } else {
+                (Quotes::Single, false)
+            };
+
+            let (escaped_str, contains_quote_chars) = if *escape {
+                shell_with_escape(name, quotes)
+            } else {
+                shell_without_escape(name, quotes, *show_control)
+            };
+
+            match (must_quote | contains_quote_chars, quotes) {
+                (true, Quotes::Single) => format!("'{}'", escaped_str),
+                (true, Quotes::Double) => format!("\"{}\"", escaped_str),
+                _ => escaped_str,
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // spell-checker:ignore (tests/words) one\'two one'two
+
+    use crate::quoting_style::{escape_name, Quotes, QuotingStyle};
+    fn get_style(s: &str) -> QuotingStyle {
+        match s {
+            "literal" => QuotingStyle::Literal {
+                show_control: false,
+            },
+            "literal-show" => QuotingStyle::Literal { show_control: true },
+            "escape" => QuotingStyle::C {
+                quotes: Quotes::None,
+            },
+            "c" => QuotingStyle::C {
+                quotes: Quotes::Double,
+            },
+            "shell" => QuotingStyle::Shell {
+                escape: false,
+                always_quote: false,
+                show_control: false,
+            },
+            "shell-show" => QuotingStyle::Shell {
+                escape: false,
+                always_quote: false,
+                show_control: true,
+            },
+            "shell-always" => QuotingStyle::Shell {
+                escape: false,
+                always_quote: true,
+                show_control: false,
+            },
+            "shell-always-show" => QuotingStyle::Shell {
+                escape: false,
+                always_quote: true,
+                show_control: true,
+            },
+            "shell-escape" => QuotingStyle::Shell {
+                escape: true,
+                always_quote: false,
+                show_control: false,
+            },
+            "shell-escape-always" => QuotingStyle::Shell {
+                escape: true,
+                always_quote: true,
+                show_control: false,
+            },
+            _ => panic!("Invalid name!"),
+        }
+    }
+
+    fn check_names(name: &str, map: Vec<(&str, &str)>) {
+        assert_eq!(
+            map.iter()
+                .map(|(_, style)| escape_name(name, &get_style(style)))
+                .collect::<Vec<String>>(),
+            map.iter()
+                .map(|(correct, _)| correct.to_string())
+                .collect::<Vec<String>>()
+        );
+    }
+
+    #[test]
+    fn test_simple_names() {
+        check_names(
+            "one_two",
+            vec![
+                ("one_two", "literal"),
+                ("one_two", "literal-show"),
+                ("one_two", "escape"),
+                ("\"one_two\"", "c"),
+                ("one_two", "shell"),
+                ("one_two", "shell-show"),
+                ("\'one_two\'", "shell-always"),
+                ("\'one_two\'", "shell-always-show"),
+                ("one_two", "shell-escape"),
+                ("\'one_two\'", "shell-escape-always"),
+            ],
+        );
+    }
+
+    #[test]
+    fn test_spaces() {
+        check_names(
+            "one two",
+            vec![
+                ("one two", "literal"),
+                ("one two", "literal-show"),
+                ("one\\ two", "escape"),
+                ("\"one two\"", "c"),
+                ("\'one two\'", "shell"),
+                ("\'one two\'", "shell-show"),
+                ("\'one two\'", "shell-always"),
+                ("\'one two\'", "shell-always-show"),
+                ("\'one two\'", "shell-escape"),
+                ("\'one two\'", "shell-escape-always"),
+            ],
+        );
+
+        check_names(
+            " one",
+            vec![
+                (" one", "literal"),
+                (" one", "literal-show"),
+                ("\\ one", "escape"),
+                ("\" one\"", "c"),
+                ("' one'", "shell"),
+                ("' one'", "shell-show"),
+                ("' one'", "shell-always"),
+                ("' one'", "shell-always-show"),
+                ("' one'", "shell-escape"),
+                ("' one'", "shell-escape-always"),
+            ],
+        );
+    }
+
+    #[test]
+    fn test_quotes() {
+        // One double quote
+        check_names(
+            "one\"two",
+            vec![
+                ("one\"two", "literal"),
+                ("one\"two", "literal-show"),
+                ("one\"two", "escape"),
+                ("\"one\\\"two\"", "c"),
+                ("'one\"two'", "shell"),
+                ("'one\"two'", "shell-show"),
+                ("'one\"two'", "shell-always"),
+                ("'one\"two'", "shell-always-show"),
+                ("'one\"two'", "shell-escape"),
+                ("'one\"two'", "shell-escape-always"),
+            ],
+        );
+
+        // One single quote
+        check_names(
+            "one\'two",
+            vec![
+                ("one'two", "literal"),
+                ("one'two", "literal-show"),
+                ("one'two", "escape"),
+                ("\"one'two\"", "c"),
+                ("\"one'two\"", "shell"),
+                ("\"one'two\"", "shell-show"),
+                ("\"one'two\"", "shell-always"),
+                ("\"one'two\"", "shell-always-show"),
+                ("\"one'two\"", "shell-escape"),
+                ("\"one'two\"", "shell-escape-always"),
+            ],
+        );
+
+        // One single quote and one double quote
+        check_names(
+            "one'two\"three",
+            vec![
+                ("one'two\"three", "literal"),
+                ("one'two\"three", "literal-show"),
+                ("one'two\"three", "escape"),
+                ("\"one'two\\\"three\"", "c"),
+                ("'one'\\''two\"three'", "shell"),
+                ("'one'\\''two\"three'", "shell-show"),
+                ("'one'\\''two\"three'", "shell-always"),
+                ("'one'\\''two\"three'", "shell-always-show"),
+                ("'one'\\''two\"three'", "shell-escape"),
+                ("'one'\\''two\"three'", "shell-escape-always"),
+            ],
+        );
+
+        // Consecutive quotes
+        check_names(
+            "one''two\"\"three",
+            vec![
+                ("one''two\"\"three", "literal"),
+                ("one''two\"\"three", "literal-show"),
+                ("one''two\"\"three", "escape"),
+                ("\"one''two\\\"\\\"three\"", "c"),
+                ("'one'\\'''\\''two\"\"three'", "shell"),
+                ("'one'\\'''\\''two\"\"three'", "shell-show"),
+                ("'one'\\'''\\''two\"\"three'", "shell-always"),
+                ("'one'\\'''\\''two\"\"three'", "shell-always-show"),
+                ("'one'\\'''\\''two\"\"three'", "shell-escape"),
+                ("'one'\\'''\\''two\"\"three'", "shell-escape-always"),
+            ],
+        );
+    }
+
+    #[test]
+    fn test_control_chars() {
+        // A simple newline
+        check_names(
+            "one\ntwo",
+            vec![
+                ("one?two", "literal"),
+                ("one\ntwo", "literal-show"),
+                ("one\\ntwo", "escape"),
+                ("\"one\\ntwo\"", "c"),
+                ("one?two", "shell"),
+                ("one\ntwo", "shell-show"),
+                ("'one?two'", "shell-always"),
+                ("'one\ntwo'", "shell-always-show"),
+                ("'one'$'\\n''two'", "shell-escape"),
+                ("'one'$'\\n''two'", "shell-escape-always"),
+            ],
+        );
+
+        // A control character followed by a special shell character
+        check_names(
+            "one\n&two",
+            vec![
+                ("one?&two", "literal"),
+                ("one\n&two", "literal-show"),
+                ("one\\n&two", "escape"),
+                ("\"one\\n&two\"", "c"),
+                ("'one?&two'", "shell"),
+                ("'one\n&two'", "shell-show"),
+                ("'one?&two'", "shell-always"),
+                ("'one\n&two'", "shell-always-show"),
+                ("'one'$'\\n''&two'", "shell-escape"),
+                ("'one'$'\\n''&two'", "shell-escape-always"),
+            ],
+        );
+
+        // The first 16 control characters. NUL is also included, even though it is of
+        // no importance for file names.
+        check_names(
+            "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+            vec![
+                ("????????????????", "literal"),
+                (
+                    "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+                    "literal-show",
+                ),
+                (
+                    "\\000\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017",
+                    "escape",
+                ),
+                (
+                    "\"\\000\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017\"",
+                    "c",
+                ),
+                ("????????????????", "shell"),
+                (
+                    "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F",
+                    "shell-show",
+                ),
+                ("'????????????????'", "shell-always"),
+                (
+                    "'\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F'",
+                    "shell-always-show",
+                ),
+                (
+                    "''$'\\000\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017'",
+                    "shell-escape",
+                ),
+                (
+                    "''$'\\000\\001\\002\\003\\004\\005\\006\\a\\b\\t\\n\\v\\f\\r\\016\\017'",
+                    "shell-escape-always",
+                ),
+            ],
+        );
+
+        // The last 16 control characters.
+        check_names(
+            "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+            vec![
+                ("????????????????", "literal"),
+                (
+                    "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+                    "literal-show",
+                ),
+                (
+                    "\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037",
+                    "escape",
+                ),
+                (
+                    "\"\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037\"",
+                    "c",
+                ),
+                ("????????????????", "shell"),
+                (
+                    "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F",
+                    "shell-show",
+                ),
+                ("'????????????????'", "shell-always"),
+                (
+                    "'\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F'",
+                    "shell-always-show",
+                ),
+                (
+                    "''$'\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037'",
+                    "shell-escape",
+                ),
+                (
+                    "''$'\\020\\021\\022\\023\\024\\025\\026\\027\\030\\031\\032\\033\\034\\035\\036\\037'",
+                    "shell-escape-always",
+                ),
+            ],
+        );
+
+        // DEL
+        check_names(
+            "\x7F",
+            vec![
+                ("?", "literal"),
+                ("\x7F", "literal-show"),
+                ("\\177", "escape"),
+                ("\"\\177\"", "c"),
+                ("?", "shell"),
+                ("\x7F", "shell-show"),
+                ("'?'", "shell-always"),
+                ("'\x7F'", "shell-always-show"),
+                ("''$'\\177'", "shell-escape"),
+                ("''$'\\177'", "shell-escape-always"),
+            ],
+        );
+    }
+
+    #[test]
+    fn test_question_mark() {
+        // A question mark must force quotes in shell and shell-always, unless
+        // it is in place of a control character (that case is already covered
+        // in other tests)
+        check_names(
+            "one?two",
+            vec![
+                ("one?two", "literal"),
+                ("one?two", "literal-show"),
+                ("one?two", "escape"),
+                ("\"one?two\"", "c"),
+                ("'one?two'", "shell"),
+                ("'one?two'", "shell-show"),
+                ("'one?two'", "shell-always"),
+                ("'one?two'", "shell-always-show"),
+                ("'one?two'", "shell-escape"),
+                ("'one?two'", "shell-escape-always"),
+            ],
+        );
+    }
+
+    #[test]
+    fn test_backslash() {
+        // Escaped in C-style, but not in Shell-style escaping
+        check_names(
+            "one\\two",
+            vec![
+                ("one\\two", "literal"),
+                ("one\\two", "literal-show"),
+                ("one\\\\two", "escape"),
+                ("\"one\\\\two\"", "c"),
+                ("'one\\two'", "shell"),
+                ("\'one\\two\'", "shell-always"),
+                ("'one\\two'", "shell-escape"),
+                ("'one\\two'", "shell-escape-always"),
+            ],
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_mkdir/mkdir.rs.html b/src/uu_mkdir/mkdir.rs.html new file mode 100644 index 000000000..0af570ebe --- /dev/null +++ b/src/uu_mkdir/mkdir.rs.html @@ -0,0 +1,267 @@ +mkdir.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Nicholas Juszczak <juszczakn@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::OsValues;
+use clap::{crate_version, App, Arg};
+use std::fs;
+use std::path::Path;
+use uucore::error::{FromIo, UResult, USimpleError};
+
+static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
+mod options {
+    pub const MODE: &str = "mode";
+    pub const PARENTS: &str = "parents";
+    pub const VERBOSE: &str = "verbose";
+    pub const DIRS: &str = "dirs";
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [USER]", uucore::execution_phrase())
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+
+    // Linux-specific options, not implemented
+    // opts.optflag("Z", "context", "set SELinux security context" +
+    // " of each created directory to CTX"),
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
+    let verbose = matches.is_present(options::VERBOSE);
+    let recursive = matches.is_present(options::PARENTS);
+
+    // Translate a ~str in octal form to u16, default to 755
+    // Not tested on Windows
+    let mode: u16 = match matches.value_of(options::MODE) {
+        Some(m) => u16::from_str_radix(m, 8)
+            .map_err(|_| USimpleError::new(1, format!("invalid mode '{}'", m)))?,
+        None => 0o755_u16,
+    };
+
+    exec(dirs, recursive, mode, verbose)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::MODE)
+                .short("m")
+                .long(options::MODE)
+                .help("set file mode (not implemented on windows)")
+                .default_value("755"),
+        )
+        .arg(
+            Arg::with_name(options::PARENTS)
+                .short("p")
+                .long(options::PARENTS)
+                .alias("parent")
+                .help("make parent directories as needed"),
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE)
+                .short("v")
+                .long(options::VERBOSE)
+                .help("print a message for each printed directory"),
+        )
+        .arg(
+            Arg::with_name(options::DIRS)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1),
+        )
+}
+
+/**
+ * Create the list of new directories
+ */
+fn exec(dirs: OsValues, recursive: bool, mode: u16, verbose: bool) -> UResult<()> {
+    for dir in dirs {
+        let path = Path::new(dir);
+        show_if_err!(mkdir(path, recursive, mode, verbose));
+    }
+    Ok(())
+}
+
+fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> UResult<()> {
+    let create_dir = if recursive {
+        fs::create_dir_all
+    } else {
+        fs::create_dir
+    };
+
+    create_dir(path).map_err_context(|| format!("cannot create directory '{}'", path.display()))?;
+
+    if verbose {
+        println!(
+            "{}: created directory '{}'",
+            uucore::util_name(),
+            path.display()
+        );
+    }
+
+    chmod(path, mode)
+}
+
+#[cfg(any(unix, target_os = "redox"))]
+fn chmod(path: &Path, mode: u16) -> UResult<()> {
+    use std::fs::{set_permissions, Permissions};
+    use std::os::unix::fs::PermissionsExt;
+
+    let mode = Permissions::from_mode(u32::from(mode));
+
+    set_permissions(path, mode)
+        .map_err_context(|| format!("cannot set permissions '{}'", path.display()))
+}
+
+#[cfg(windows)]
+fn chmod(_path: &Path, _mode: u16) -> UResult<()> {
+    // chmod on Windows only sets the readonly flag, which isn't even honored on directories
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_mkfifo/mkfifo.rs.html b/src/uu_mkfifo/mkfifo.rs.html new file mode 100644 index 000000000..434bbf633 --- /dev/null +++ b/src/uu_mkfifo/mkfifo.rs.html @@ -0,0 +1,207 @@ +mkfifo.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Gehring <mg@ebfe.org>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use libc::mkfifo;
+use std::ffi::CString;
+use uucore::InvalidEncodingHandling;
+
+static NAME: &str = "mkfifo";
+static USAGE: &str = "mkfifo [OPTION]... NAME...";
+static SUMMARY: &str = "Create a FIFO with the given name.";
+
+mod options {
+    pub static MODE: &str = "mode";
+    pub static SE_LINUX_SECURITY_CONTEXT: &str = "Z";
+    pub static CONTEXT: &str = "context";
+    pub static FIFO: &str = "fifo";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    if matches.is_present(options::CONTEXT) {
+        crash!(1, "--context is not implemented");
+    }
+    if matches.is_present(options::SE_LINUX_SECURITY_CONTEXT) {
+        crash!(1, "-Z is not implemented");
+    }
+
+    let mode = match matches.value_of(options::MODE) {
+        Some(m) => match usize::from_str_radix(m, 8) {
+            Ok(m) => m,
+            Err(e) => {
+                show_error!("invalid mode: {}", e);
+                return 1;
+            }
+        },
+        None => 0o666,
+    };
+
+    let fifos: Vec<String> = match matches.values_of(options::FIFO) {
+        Some(v) => v.clone().map(|s| s.to_owned()).collect(),
+        None => crash!(1, "missing operand"),
+    };
+
+    let mut exit_code = 0;
+    for f in fifos {
+        let err = unsafe {
+            let name = CString::new(f.as_bytes()).unwrap();
+            mkfifo(name.as_ptr(), mode as libc::mode_t)
+        };
+        if err == -1 {
+            show_error!("cannot create fifo '{}': File exists", f);
+            exit_code = 1;
+        }
+    }
+
+    exit_code
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(USAGE)
+        .about(SUMMARY)
+        .arg(
+            Arg::with_name(options::MODE)
+                .short("m")
+                .long(options::MODE)
+                .help("file permissions for the fifo")
+                .default_value("0666")
+                .value_name("0666"),
+        )
+        .arg(
+            Arg::with_name(options::SE_LINUX_SECURITY_CONTEXT)
+                .short(options::SE_LINUX_SECURITY_CONTEXT)
+                .help("set the SELinux security context to default type"),
+        )
+        .arg(
+            Arg::with_name(options::CONTEXT)
+                .long(options::CONTEXT)
+                .value_name("CTX")
+                .help(
+                    "like -Z, or if CTX is specified then set the SELinux \
+                    or SMACK security context to CTX",
+                ),
+        )
+        .arg(Arg::with_name(options::FIFO).hidden(true).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_mknod/mknod.rs.html b/src/uu_mknod/mknod.rs.html new file mode 100644 index 000000000..22793f633 --- /dev/null +++ b/src/uu_mknod/mknod.rs.html @@ -0,0 +1,463 @@ +mknod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO
+
+#[macro_use]
+extern crate uucore;
+
+use std::ffi::CString;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use libc::{dev_t, mode_t};
+use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};
+
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Create the special file NAME of the given TYPE.";
+static USAGE: &str = "mknod [OPTION]... NAME TYPE [MAJOR MINOR]";
+static LONG_HELP: &str = "Mandatory arguments to long options are mandatory for short options too.
+-m, --mode=MODE    set file permission bits to MODE, not a=rw - umask
+--help     display this help and exit
+--version  output version information and exit
+
+Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they
+must be omitted when TYPE is p.  If MAJOR or MINOR begins with 0x or 0X,
+it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;
+otherwise, as decimal.  TYPE may be:
+
+b      create a block (buffered) special file
+c, u   create a character (unbuffered) special file
+p      create a FIFO
+
+NOTE: your shell may have its own version of mknod, which usually supersedes
+the version described here.  Please refer to your shell's documentation
+for details about the options it supports.
+";
+
+const MODE_RW_UGO: mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+
+#[inline(always)]
+fn makedev(maj: u64, min: u64) -> dev_t {
+    // pick up from <sys/sysmacros.h>
+    ((min & 0xff) | ((maj & 0xfff) << 8) | ((min & !0xff) << 12) | ((maj & !0xfff) << 32)) as dev_t
+}
+
+#[cfg(windows)]
+fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
+    panic!("Unsupported for windows platform")
+}
+
+#[cfg(unix)]
+fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
+    let c_str = CString::new(file_name).expect("Failed to convert to CString");
+
+    // the user supplied a mode
+    let set_umask = mode & MODE_RW_UGO != MODE_RW_UGO;
+
+    unsafe {
+        // store prev umask
+        let last_umask = if set_umask { libc::umask(0) } else { 0 };
+
+        let errno = libc::mknod(c_str.as_ptr(), mode, dev);
+
+        // set umask back to original value
+        if set_umask {
+            libc::umask(last_umask);
+        }
+
+        if errno == -1 {
+            let c_str = CString::new(uucore::execution_phrase().as_bytes())
+                .expect("Failed to convert to CString");
+            // shows the error from the mknod syscall
+            libc::perror(c_str.as_ptr());
+        }
+        errno
+    }
+}
+
+#[allow(clippy::cognitive_complexity)]
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+    // Linux-specific options, not implemented
+    // opts.optflag("Z", "", "set the SELinux security context to default type");
+    // opts.optopt("", "context", "like -Z, or if CTX is specified then set the SELinux or SMACK security context to CTX");
+
+    let matches = uu_app().get_matches_from(args);
+
+    let mode = match get_mode(&matches) {
+        Ok(mode) => mode,
+        Err(err) => {
+            show_error!("{}", err);
+            return 1;
+        }
+    };
+
+    let file_name = matches.value_of("name").expect("Missing argument 'NAME'");
+
+    // Only check the first character, to allow mnemonic usage like
+    // 'mknod /dev/rst0 character 18 0'.
+    let ch = matches
+        .value_of("type")
+        .expect("Missing argument 'TYPE'")
+        .chars()
+        .next()
+        .expect("Failed to get the first char");
+
+    if ch == 'p' {
+        if matches.is_present("major") || matches.is_present("minor") {
+            eprintln!("Fifos do not have major and minor device numbers.");
+            eprintln!(
+                "Try '{} --help' for more information.",
+                uucore::execution_phrase()
+            );
+            1
+        } else {
+            _mknod(file_name, S_IFIFO | mode, 0)
+        }
+    } else {
+        match (matches.value_of("major"), matches.value_of("minor")) {
+            (None, None) | (_, None) | (None, _) => {
+                eprintln!("Special files require major and minor device numbers.");
+                eprintln!(
+                    "Try '{} --help' for more information.",
+                    uucore::execution_phrase()
+                );
+                1
+            }
+            (Some(major), Some(minor)) => {
+                let major = major.parse::<u64>().expect("validated by clap");
+                let minor = minor.parse::<u64>().expect("validated by clap");
+
+                let dev = makedev(major, minor);
+                if ch == 'b' {
+                    // block special file
+                    _mknod(file_name, S_IFBLK | mode, dev)
+                } else if ch == 'c' || ch == 'u' {
+                    // char special file
+                    _mknod(file_name, S_IFCHR | mode, dev)
+                } else {
+                    unreachable!("{} was validated to be only b, c or u", ch);
+                }
+            }
+        }
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .usage(USAGE)
+        .after_help(LONG_HELP)
+        .about(ABOUT)
+        .arg(
+            Arg::with_name("mode")
+                .short("m")
+                .long("mode")
+                .value_name("MODE")
+                .help("set file permission bits to MODE, not a=rw - umask"),
+        )
+        .arg(
+            Arg::with_name("name")
+                .value_name("NAME")
+                .help("name of the new file")
+                .required(true)
+                .index(1),
+        )
+        .arg(
+            Arg::with_name("type")
+                .value_name("TYPE")
+                .help("type of the new file (b, c, u or p)")
+                .required(true)
+                .validator(valid_type)
+                .index(2),
+        )
+        .arg(
+            Arg::with_name("major")
+                .value_name("MAJOR")
+                .help("major file type")
+                .validator(valid_u64)
+                .index(3),
+        )
+        .arg(
+            Arg::with_name("minor")
+                .value_name("MINOR")
+                .help("minor file type")
+                .validator(valid_u64)
+                .index(4),
+        )
+}
+
+fn get_mode(matches: &ArgMatches) -> Result<mode_t, String> {
+    match matches.value_of("mode") {
+        None => Ok(MODE_RW_UGO),
+        Some(str_mode) => uucore::mode::parse_mode(str_mode)
+            .map_err(|e| format!("invalid mode ({})", e))
+            .and_then(|mode| {
+                if mode > 0o777 {
+                    Err("mode must specify only file permission bits".to_string())
+                } else {
+                    Ok(mode)
+                }
+            }),
+    }
+}
+
+fn valid_type(tpe: String) -> Result<(), String> {
+    // Only check the first character, to allow mnemonic usage like
+    // 'mknod /dev/rst0 character 18 0'.
+    tpe.chars()
+        .next()
+        .ok_or_else(|| "missing device type".to_string())
+        .and_then(|first_char| {
+            if vec!['b', 'c', 'u', 'p'].contains(&first_char) {
+                Ok(())
+            } else {
+                Err(format!("invalid device type '{}'", tpe))
+            }
+        })
+}
+
+fn valid_u64(num: String) -> Result<(), String> {
+    num.parse::<u64>().map(|_| ()).map_err(|_| num)
+}
+
+
\ No newline at end of file diff --git a/src/uu_mktemp/mktemp.rs.html b/src/uu_mktemp/mktemp.rs.html new file mode 100644 index 000000000..834458f9f --- /dev/null +++ b/src/uu_mktemp/mktemp.rs.html @@ -0,0 +1,563 @@ +mktemp.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Sunrin SHIMURA
+// Collaborator: Jian Zeng
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (paths) GPGHome
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use uucore::error::{FromIo, UError, UResult};
+
+use std::env;
+use std::error::Error;
+use std::fmt::Display;
+use std::iter;
+use std::path::{is_separator, PathBuf};
+
+use rand::Rng;
+use tempfile::Builder;
+
+static ABOUT: &str = "create a temporary file or directory.";
+
+static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX";
+
+static OPT_DIRECTORY: &str = "directory";
+static OPT_DRY_RUN: &str = "dry-run";
+static OPT_QUIET: &str = "quiet";
+static OPT_SUFFIX: &str = "suffix";
+static OPT_TMPDIR: &str = "tmpdir";
+static OPT_T: &str = "t";
+
+static ARG_TEMPLATE: &str = "template";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [TEMPLATE]", uucore::execution_phrase())
+}
+
+#[derive(Debug)]
+enum MkTempError {
+    PersistError(PathBuf),
+    MustEndInX(String),
+    TooFewXs(String),
+    ContainsDirSeparator(String),
+    InvalidTemplate(String),
+}
+
+impl UError for MkTempError {}
+
+impl Error for MkTempError {}
+
+impl Display for MkTempError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use MkTempError::*;
+        match self {
+            PersistError(p) => write!(f, "could not persist file '{}'", p.display()),
+            MustEndInX(s) => write!(f, "with --suffix, template '{}' must end in X", s),
+            TooFewXs(s) => write!(f, "too few X's in template '{}'", s),
+            ContainsDirSeparator(s) => {
+                write!(f, "invalid suffix '{}', contains directory separator", s)
+            }
+            InvalidTemplate(s) => write!(
+                f,
+                "invalid template, '{}'; with --tmpdir, it may not be absolute",
+                s
+            ),
+        }
+    }
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let template = matches.value_of(ARG_TEMPLATE).unwrap();
+    let tmpdir = matches.value_of(OPT_TMPDIR).unwrap_or_default();
+
+    let (template, mut tmpdir) = if matches.is_present(OPT_TMPDIR)
+        && !PathBuf::from(tmpdir).is_dir() // if a temp dir is provided, it must be an actual path
+        && tmpdir.contains("XXX")
+    // If this is a template, it has to contain at least 3 X
+        && template == DEFAULT_TEMPLATE
+    // That means that clap does not think we provided a template
+    {
+        // Special case to workaround a limitation of clap when doing
+        // mktemp --tmpdir apt-key-gpghome.XXX
+        // The behavior should be
+        // mktemp --tmpdir $TMPDIR apt-key-gpghome.XX
+        // As --tmpdir is empty
+        //
+        // Fixed in clap 3
+        // See https://github.com/clap-rs/clap/pull/1587
+        let tmp = env::temp_dir();
+        (tmpdir, tmp)
+    } else if !matches.is_present(OPT_TMPDIR) {
+        let tmp = env::temp_dir();
+        (template, tmp)
+    } else {
+        (template, PathBuf::from(tmpdir))
+    };
+
+    let make_dir = matches.is_present(OPT_DIRECTORY);
+    let dry_run = matches.is_present(OPT_DRY_RUN);
+    let suppress_file_err = matches.is_present(OPT_QUIET);
+
+    let (prefix, rand, suffix) = parse_template(template, matches.value_of(OPT_SUFFIX))?;
+
+    if matches.is_present(OPT_TMPDIR) && PathBuf::from(prefix).is_absolute() {
+        return Err(MkTempError::InvalidTemplate(template.into()).into());
+    }
+
+    if matches.is_present(OPT_T) {
+        tmpdir = env::temp_dir()
+    }
+
+    let res = if dry_run {
+        dry_exec(tmpdir, prefix, rand, suffix)
+    } else {
+        exec(tmpdir, prefix, rand, suffix, make_dir)
+    };
+
+    if suppress_file_err {
+        // Mapping all UErrors to ExitCodes prevents the errors from being printed
+        res.map_err(|e| e.code().into())
+    } else {
+        res
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_DIRECTORY)
+                .short("d")
+                .long(OPT_DIRECTORY)
+                .help("Make a directory instead of a file"),
+        )
+        .arg(
+            Arg::with_name(OPT_DRY_RUN)
+                .short("u")
+                .long(OPT_DRY_RUN)
+                .help("do not create anything; merely print a name (unsafe)"),
+        )
+        .arg(
+            Arg::with_name(OPT_QUIET)
+                .short("q")
+                .long("quiet")
+                .help("Fail silently if an error occurs."),
+        )
+        .arg(
+            Arg::with_name(OPT_SUFFIX)
+                .long(OPT_SUFFIX)
+                .help(
+                    "append SUFFIX to TEMPLATE; SUFFIX must not contain a path separator. \
+                     This option is implied if TEMPLATE does not end with X.",
+                )
+                .value_name("SUFFIX"),
+        )
+        .arg(
+            Arg::with_name(OPT_TMPDIR)
+                .short("p")
+                .long(OPT_TMPDIR)
+                .help(
+                    "interpret TEMPLATE relative to DIR; if DIR is not specified, use \
+                     $TMPDIR ($TMP on windows) if set, else /tmp. With this option, TEMPLATE must not \
+                     be an absolute name; unlike with -t, TEMPLATE may contain \
+                     slashes, but mktemp creates only the final component",
+                )
+                .value_name("DIR"),
+        )
+        .arg(Arg::with_name(OPT_T).short(OPT_T).help(
+            "Generate a template (using the supplied prefix and TMPDIR (TMP on windows) if set) \
+             to create a filename template [deprecated]",
+        ))
+        .arg(
+            Arg::with_name(ARG_TEMPLATE)
+                .multiple(false)
+                .takes_value(true)
+                .max_values(1)
+                .default_value(DEFAULT_TEMPLATE),
+        )
+}
+
+fn parse_template<'a>(
+    temp: &'a str,
+    suffix: Option<&'a str>,
+) -> UResult<(&'a str, usize, &'a str)> {
+    let right = match temp.rfind('X') {
+        Some(r) => r + 1,
+        None => return Err(MkTempError::TooFewXs(temp.into()).into()),
+    };
+    let left = temp[..right].rfind(|c| c != 'X').map_or(0, |i| i + 1);
+    let prefix = &temp[..left];
+    let rand = right - left;
+
+    if rand < 3 {
+        return Err(MkTempError::TooFewXs(temp.into()).into());
+    }
+
+    let mut suf = &temp[right..];
+
+    if let Some(s) = suffix {
+        if suf.is_empty() {
+            suf = s;
+        } else {
+            return Err(MkTempError::MustEndInX(temp.into()).into());
+        }
+    };
+
+    if suf.chars().any(is_separator) {
+        return Err(MkTempError::ContainsDirSeparator(suf.into()).into());
+    }
+
+    Ok((prefix, rand, suf))
+}
+
+pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) -> UResult<()> {
+    let len = prefix.len() + suffix.len() + rand;
+    let mut buf = String::with_capacity(len);
+    buf.push_str(prefix);
+    buf.extend(iter::repeat('X').take(rand));
+    buf.push_str(suffix);
+
+    // Randomize.
+    unsafe {
+        // We guarantee utf8.
+        let bytes = &mut buf.as_mut_vec()[prefix.len()..prefix.len() + rand];
+        rand::thread_rng().fill(bytes);
+        for byte in bytes.iter_mut() {
+            *byte = match *byte % 62 {
+                v @ 0..=9 => (v + b'0'),
+                v @ 10..=35 => (v - 10 + b'a'),
+                v @ 36..=61 => (v - 36 + b'A'),
+                _ => unreachable!(),
+            }
+        }
+    }
+    tmpdir.push(buf);
+    println!("{}", tmpdir.display());
+    Ok(())
+}
+
+fn exec(dir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
+    let context = || {
+        format!(
+            "failed to create file via template '{}{}{}'",
+            prefix,
+            "X".repeat(rand),
+            suffix
+        )
+    };
+
+    let mut builder = Builder::new();
+    builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
+
+    let path = if make_dir {
+        builder
+            .tempdir_in(&dir)
+            .map_err_context(context)?
+            .into_path() // `into_path` consumes the TempDir without removing it
+    } else {
+        builder
+            .tempfile_in(&dir)
+            .map_err_context(context)?
+            .keep() // `keep` ensures that the file is not deleted
+            .map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))?
+            .1
+    };
+    println!("{}", path.display());
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_more/more.rs.html b/src/uu_more/more.rs.html new file mode 100644 index 000000000..4533fa45a --- /dev/null +++ b/src/uu_more/more.rs.html @@ -0,0 +1,925 @@ +more.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Martin Kysel <code@martinkysel.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE file
+//  * that was distributed with this source code.
+
+// spell-checker:ignore (methods) isnt
+
+#[macro_use]
+extern crate uucore;
+
+use std::{
+    fs::File,
+    io::{stdin, stdout, BufReader, Read, Stdout, Write},
+    path::Path,
+    time::Duration,
+};
+
+#[cfg(all(unix, not(target_os = "fuchsia")))]
+extern crate nix;
+
+use clap::{crate_version, App, Arg};
+use crossterm::{
+    event::{self, Event, KeyCode, KeyEvent, KeyModifiers},
+    execute, queue,
+    style::Attribute,
+    terminal,
+};
+
+use unicode_segmentation::UnicodeSegmentation;
+use unicode_width::UnicodeWidthStr;
+
+const BELL: &str = "\x07";
+
+pub mod options {
+    pub const SILENT: &str = "silent";
+    pub const LOGICAL: &str = "logical";
+    pub const NO_PAUSE: &str = "no-pause";
+    pub const PRINT_OVER: &str = "print-over";
+    pub const CLEAN_PRINT: &str = "clean-print";
+    pub const SQUEEZE: &str = "squeeze";
+    pub const PLAIN: &str = "plain";
+    pub const LINES: &str = "lines";
+    pub const NUMBER: &str = "number";
+    pub const PATTERN: &str = "pattern";
+    pub const FROM_LINE: &str = "from-line";
+    pub const FILES: &str = "files";
+}
+
+const MULTI_FILE_TOP_PROMPT: &str = "::::::::::::::\n{}\n::::::::::::::\n";
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let matches = uu_app().get_matches_from(args);
+
+    let mut buff = String::new();
+    let silent = matches.is_present(options::SILENT);
+    if let Some(files) = matches.values_of(options::FILES) {
+        let mut stdout = setup_term();
+        let length = files.len();
+
+        let mut files_iter = files.peekable();
+        while let (Some(file), next_file) = (files_iter.next(), files_iter.peek()) {
+            let file = Path::new(file);
+            if file.is_dir() {
+                terminal::disable_raw_mode().unwrap();
+                show_usage_error!("'{}' is a directory.", file.display());
+                return 1;
+            }
+            if !file.exists() {
+                terminal::disable_raw_mode().unwrap();
+                show_error!("cannot open {}: No such file or directory", file.display());
+                return 1;
+            }
+            if length > 1 {
+                buff.push_str(&MULTI_FILE_TOP_PROMPT.replace("{}", file.to_str().unwrap()));
+            }
+            let mut reader = BufReader::new(File::open(file).unwrap());
+            reader.read_to_string(&mut buff).unwrap();
+            more(&buff, &mut stdout, next_file.copied(), silent);
+            buff.clear();
+        }
+        reset_term(&mut stdout);
+    } else if atty::isnt(atty::Stream::Stdin) {
+        stdin().read_to_string(&mut buff).unwrap();
+        let mut stdout = setup_term();
+        more(&buff, &mut stdout, None, silent);
+        reset_term(&mut stdout);
+    } else {
+        show_usage_error!("bad usage");
+    }
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .about("A file perusal filter for CRT viewing.")
+        .version(crate_version!())
+        .arg(
+            Arg::with_name(options::SILENT)
+                .short("d")
+                .long(options::SILENT)
+                .help("Display help instead of ringing bell"),
+        )
+        // The commented arguments below are unimplemented:
+        /*
+        .arg(
+            Arg::with_name(options::LOGICAL)
+                .short("f")
+                .long(options::LOGICAL)
+                .help("Count logical rather than screen lines"),
+        )
+        .arg(
+            Arg::with_name(options::NO_PAUSE)
+                .short("l")
+                .long(options::NO_PAUSE)
+                .help("Suppress pause after form feed"),
+        )
+        .arg(
+            Arg::with_name(options::PRINT_OVER)
+                .short("c")
+                .long(options::PRINT_OVER)
+                .help("Do not scroll, display text and clean line ends"),
+        )
+        .arg(
+            Arg::with_name(options::CLEAN_PRINT)
+                .short("p")
+                .long(options::CLEAN_PRINT)
+                .help("Do not scroll, clean screen and display text"),
+        )
+        .arg(
+            Arg::with_name(options::SQUEEZE)
+                .short("s")
+                .long(options::SQUEEZE)
+                .help("Squeeze multiple blank lines into one"),
+        )
+        .arg(
+            Arg::with_name(options::PLAIN)
+                .short("u")
+                .long(options::PLAIN)
+                .help("Suppress underlining and bold"),
+        )
+        .arg(
+            Arg::with_name(options::LINES)
+                .short("n")
+                .long(options::LINES)
+                .value_name("number")
+                .takes_value(true)
+                .help("The number of lines per screen full"),
+        )
+        .arg(
+            Arg::with_name(options::NUMBER)
+                .allow_hyphen_values(true)
+                .long(options::NUMBER)
+                .required(false)
+                .takes_value(true)
+                .help("Same as --lines"),
+        )
+        .arg(
+            Arg::with_name(options::FROM_LINE)
+                .short("F")
+                .allow_hyphen_values(true)
+                .required(false)
+                .takes_value(true)
+                .value_name("number")
+                .help("Display file beginning from line number"),
+        )
+        .arg(
+            Arg::with_name(options::PATTERN)
+                .short("P")
+                .allow_hyphen_values(true)
+                .required(false)
+                .takes_value(true)
+                .help("Display file beginning from pattern match"),
+        )
+        */
+        .arg(
+            Arg::with_name(options::FILES)
+                .required(false)
+                .multiple(true)
+                .help("Path to the files to be read"),
+        )
+}
+
+#[cfg(not(target_os = "fuchsia"))]
+fn setup_term() -> std::io::Stdout {
+    let stdout = stdout();
+    terminal::enable_raw_mode().unwrap();
+    stdout
+}
+
+#[cfg(target_os = "fuchsia")]
+#[inline(always)]
+fn setup_term() -> usize {
+    0
+}
+
+#[cfg(not(target_os = "fuchsia"))]
+fn reset_term(stdout: &mut std::io::Stdout) {
+    terminal::disable_raw_mode().unwrap();
+    // Clear the prompt
+    queue!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
+    // Move cursor to the beginning without printing new line
+    print!("\r");
+    stdout.flush().unwrap();
+}
+
+#[cfg(target_os = "fuchsia")]
+#[inline(always)]
+fn reset_term(_: &mut usize) {}
+
+fn more(buff: &str, mut stdout: &mut Stdout, next_file: Option<&str>, silent: bool) {
+    let (cols, rows) = terminal::size().unwrap();
+    let lines = break_buff(buff, usize::from(cols));
+
+    let mut pager = Pager::new(rows, lines, next_file, silent);
+    pager.draw(stdout, None);
+    if pager.should_close() {
+        return;
+    }
+
+    loop {
+        let mut wrong_key = None;
+        if event::poll(Duration::from_millis(10)).unwrap() {
+            match event::read().unwrap() {
+                Event::Key(KeyEvent {
+                    code: KeyCode::Char('q'),
+                    modifiers: KeyModifiers::NONE,
+                })
+                | Event::Key(KeyEvent {
+                    code: KeyCode::Char('c'),
+                    modifiers: KeyModifiers::CONTROL,
+                }) => {
+                    reset_term(&mut stdout);
+                    std::process::exit(0);
+                }
+                Event::Key(KeyEvent {
+                    code: KeyCode::Down,
+                    modifiers: KeyModifiers::NONE,
+                })
+                | Event::Key(KeyEvent {
+                    code: KeyCode::Char(' '),
+                    modifiers: KeyModifiers::NONE,
+                }) => {
+                    if pager.should_close() {
+                        return;
+                    } else {
+                        pager.page_down();
+                    }
+                }
+                Event::Key(KeyEvent {
+                    code: KeyCode::Up,
+                    modifiers: KeyModifiers::NONE,
+                }) => {
+                    pager.page_up();
+                }
+                Event::Resize(col, row) => {
+                    pager.page_resize(col, row);
+                }
+                Event::Key(KeyEvent {
+                    code: KeyCode::Char(k),
+                    ..
+                }) => wrong_key = Some(k),
+                _ => continue,
+            }
+
+            pager.draw(stdout, wrong_key);
+        }
+    }
+}
+
+struct Pager<'a> {
+    // The current line at the top of the screen
+    upper_mark: usize,
+    // The number of rows that fit on the screen
+    content_rows: u16,
+    lines: Vec<String>,
+    next_file: Option<&'a str>,
+    line_count: usize,
+    silent: bool,
+}
+
+impl<'a> Pager<'a> {
+    fn new(rows: u16, lines: Vec<String>, next_file: Option<&'a str>, silent: bool) -> Self {
+        let line_count = lines.len();
+        Self {
+            upper_mark: 0,
+            content_rows: rows.saturating_sub(1),
+            lines,
+            next_file,
+            line_count,
+            silent,
+        }
+    }
+
+    fn should_close(&mut self) -> bool {
+        self.upper_mark
+            .saturating_add(self.content_rows.into())
+            .ge(&self.line_count)
+    }
+
+    fn page_down(&mut self) {
+        self.upper_mark = self.upper_mark.saturating_add(self.content_rows.into());
+    }
+
+    fn page_up(&mut self) {
+        self.upper_mark = self.upper_mark.saturating_sub(self.content_rows.into());
+    }
+
+    // TODO: Deal with column size changes.
+    fn page_resize(&mut self, _: u16, row: u16) {
+        self.content_rows = row.saturating_sub(1);
+    }
+
+    fn draw(&self, stdout: &mut std::io::Stdout, wrong_key: Option<char>) {
+        let lower_mark = self
+            .line_count
+            .min(self.upper_mark.saturating_add(self.content_rows.into()));
+        self.draw_lines(stdout);
+        self.draw_prompt(stdout, lower_mark, wrong_key);
+        stdout.flush().unwrap();
+    }
+
+    fn draw_lines(&self, stdout: &mut std::io::Stdout) {
+        execute!(stdout, terminal::Clear(terminal::ClearType::CurrentLine)).unwrap();
+        let displayed_lines = self
+            .lines
+            .iter()
+            .skip(self.upper_mark)
+            .take(self.content_rows.into());
+
+        for line in displayed_lines {
+            stdout
+                .write_all(format!("\r{}\n", line).as_bytes())
+                .unwrap();
+        }
+    }
+
+    fn draw_prompt(&self, stdout: &mut Stdout, lower_mark: usize, wrong_key: Option<char>) {
+        let status_inner = if lower_mark == self.line_count {
+            format!("Next file: {}", self.next_file.unwrap_or_default())
+        } else {
+            format!(
+                "{}%",
+                (lower_mark as f64 / self.line_count as f64 * 100.0).round() as u16
+            )
+        };
+
+        let status = format!("--More--({})", status_inner);
+
+        let banner = match (self.silent, wrong_key) {
+            (true, Some(key)) => format!(
+                "{} [Unknown key: '{}'. Press 'h' for instructions. (unimplemented)]",
+                status, key
+            ),
+            (true, None) => format!("{}[Press space to continue, 'q' to quit.]", status),
+            (false, Some(_)) => format!("{}{}", status, BELL),
+            (false, None) => status,
+        };
+
+        write!(
+            stdout,
+            "\r{}{}{}",
+            Attribute::Reverse,
+            banner,
+            Attribute::Reset
+        )
+        .unwrap();
+    }
+}
+
+// Break the lines on the cols of the terminal
+fn break_buff(buff: &str, cols: usize) -> Vec<String> {
+    let mut lines = Vec::with_capacity(buff.lines().count());
+
+    for l in buff.lines() {
+        lines.append(&mut break_line(l, cols));
+    }
+    lines
+}
+
+fn break_line(line: &str, cols: usize) -> Vec<String> {
+    let width = UnicodeWidthStr::width(line);
+    let mut lines = Vec::new();
+    if width < cols {
+        lines.push(line.to_string());
+        return lines;
+    }
+
+    let gr_idx = UnicodeSegmentation::grapheme_indices(line, true);
+    let mut last_index = 0;
+    let mut total_width = 0;
+    for (index, grapheme) in gr_idx {
+        let width = UnicodeWidthStr::width(grapheme);
+        total_width += width;
+
+        if total_width > cols {
+            lines.push(line[last_index..index].to_string());
+            last_index = index;
+            total_width = width;
+        }
+    }
+
+    if last_index != line.len() {
+        lines.push(line[last_index..].to_string());
+    }
+    lines
+}
+
+#[cfg(test)]
+mod tests {
+    use super::break_line;
+    use unicode_width::UnicodeWidthStr;
+
+    #[test]
+    fn test_break_lines_long() {
+        let mut test_string = String::with_capacity(100);
+        for _ in 0..200 {
+            test_string.push('#');
+        }
+
+        let lines = break_line(&test_string, 80);
+        let widths: Vec<usize> = lines
+            .iter()
+            .map(|s| UnicodeWidthStr::width(&s[..]))
+            .collect();
+
+        assert_eq!((80, 80, 40), (widths[0], widths[1], widths[2]));
+    }
+
+    #[test]
+    fn test_break_lines_short() {
+        let mut test_string = String::with_capacity(100);
+        for _ in 0..20 {
+            test_string.push('#');
+        }
+
+        let lines = break_line(&test_string, 80);
+
+        assert_eq!(20, lines[0].len());
+    }
+
+    #[test]
+    fn test_break_line_zwj() {
+        let mut test_string = String::with_capacity(1100);
+        for _ in 0..20 {
+            test_string.push_str("👩🏻‍🔬");
+        }
+
+        let lines = break_line(&test_string, 80);
+
+        let widths: Vec<usize> = lines
+            .iter()
+            .map(|s| UnicodeWidthStr::width(&s[..]))
+            .collect();
+
+        // Each 👩🏻‍🔬 is 6 character width it break line to the closest number to 80 => 6 * 13 = 78
+        assert_eq!((78, 42), (widths[0], widths[1]));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_mv/mv.rs.html b/src/uu_mv/mv.rs.html new file mode 100644 index 000000000..ccf064603 --- /dev/null +++ b/src/uu_mv/mv.rs.html @@ -0,0 +1,983 @@ +mv.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Orvar Segerström <orvarsegerstrom@gmail.com>
+// (c) Sokovikov Evgeniy  <skv-headless@yandex.ru>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) sourcepath targetpath
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use std::env;
+use std::fs;
+use std::io::{self, stdin};
+#[cfg(unix)]
+use std::os::unix;
+#[cfg(windows)]
+use std::os::windows;
+use std::path::{Path, PathBuf};
+use uucore::backup_control::{self, BackupMode};
+
+use fs_extra::dir::{move_dir, CopyOptions as DirCopyOptions};
+
+pub struct Behavior {
+    overwrite: OverwriteMode,
+    backup: BackupMode,
+    suffix: String,
+    update: bool,
+    target_dir: Option<String>,
+    no_target_dir: bool,
+    verbose: bool,
+}
+
+#[derive(Clone, Eq, PartialEq)]
+pub enum OverwriteMode {
+    NoClobber,
+    Interactive,
+    Force,
+}
+
+static ABOUT: &str = "Move SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.";
+static LONG_HELP: &str = "";
+
+static OPT_BACKUP: &str = "backup";
+static OPT_BACKUP_NO_ARG: &str = "b";
+static OPT_FORCE: &str = "force";
+static OPT_INTERACTIVE: &str = "interactive";
+static OPT_NO_CLOBBER: &str = "no-clobber";
+static OPT_STRIP_TRAILING_SLASHES: &str = "strip-trailing-slashes";
+static OPT_SUFFIX: &str = "suffix";
+static OPT_TARGET_DIRECTORY: &str = "target-directory";
+static OPT_NO_TARGET_DIRECTORY: &str = "no-target-directory";
+static OPT_UPDATE: &str = "update";
+static OPT_VERBOSE: &str = "verbose";
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [-T] SOURCE DEST
+{0} [OPTION]... SOURCE... DIRECTORY
+{0} [OPTION]... -t DIRECTORY SOURCE...",
+        uucore::execution_phrase()
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app()
+        .after_help(&*format!(
+            "{}\n{}",
+            LONG_HELP,
+            backup_control::BACKUP_CONTROL_LONG_HELP
+        ))
+        .usage(&usage[..])
+        .get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let overwrite_mode = determine_overwrite_mode(&matches);
+    let backup_mode = backup_control::determine_backup_mode(
+        matches.is_present(OPT_BACKUP_NO_ARG),
+        matches.is_present(OPT_BACKUP),
+        matches.value_of(OPT_BACKUP),
+    );
+    let backup_mode = match backup_mode {
+        Err(err) => {
+            show_usage_error!("{}", err);
+            return 1;
+        }
+        Ok(mode) => mode,
+    };
+
+    if overwrite_mode == OverwriteMode::NoClobber && backup_mode != BackupMode::NoBackup {
+        show_usage_error!("options --backup and --no-clobber are mutually exclusive");
+        return 1;
+    }
+
+    let backup_suffix = backup_control::determine_backup_suffix(matches.value_of(OPT_SUFFIX));
+
+    let behavior = Behavior {
+        overwrite: overwrite_mode,
+        backup: backup_mode,
+        suffix: backup_suffix,
+        update: matches.is_present(OPT_UPDATE),
+        target_dir: matches.value_of(OPT_TARGET_DIRECTORY).map(String::from),
+        no_target_dir: matches.is_present(OPT_NO_TARGET_DIRECTORY),
+        verbose: matches.is_present(OPT_VERBOSE),
+    };
+
+    let paths: Vec<PathBuf> = {
+        fn strip_slashes(p: &Path) -> &Path {
+            p.components().as_path()
+        }
+        let to_owned = |p: &Path| p.to_owned();
+        let paths = files.iter().map(Path::new);
+
+        if matches.is_present(OPT_STRIP_TRAILING_SLASHES) {
+            paths.map(strip_slashes).map(to_owned).collect()
+        } else {
+            paths.map(to_owned).collect()
+        }
+    };
+
+    exec(&paths[..], behavior)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+    .arg(
+            Arg::with_name(OPT_BACKUP)
+            .long(OPT_BACKUP)
+            .help("make a backup of each existing destination file")
+            .takes_value(true)
+            .require_equals(true)
+            .min_values(0)
+            .value_name("CONTROL")
+    )
+    .arg(
+            Arg::with_name(OPT_BACKUP_NO_ARG)
+            .short(OPT_BACKUP_NO_ARG)
+            .help("like --backup but does not accept an argument")
+    )
+    .arg(
+            Arg::with_name(OPT_FORCE)
+            .short("f")
+            .long(OPT_FORCE)
+            .help("do not prompt before overwriting")
+    )
+    .arg(
+            Arg::with_name(OPT_INTERACTIVE)
+            .short("i")
+            .long(OPT_INTERACTIVE)
+            .help("prompt before override")
+    )
+    .arg(
+            Arg::with_name(OPT_NO_CLOBBER).short("n")
+            .long(OPT_NO_CLOBBER)
+            .help("do not overwrite an existing file")
+    )
+    .arg(
+            Arg::with_name(OPT_STRIP_TRAILING_SLASHES)
+            .long(OPT_STRIP_TRAILING_SLASHES)
+            .help("remove any trailing slashes from each SOURCE argument")
+    )
+    .arg(
+            Arg::with_name(OPT_SUFFIX)
+            .short("S")
+            .long(OPT_SUFFIX)
+            .help("override the usual backup suffix")
+            .takes_value(true)
+            .value_name("SUFFIX")
+    )
+    .arg(
+        Arg::with_name(OPT_TARGET_DIRECTORY)
+        .short("t")
+        .long(OPT_TARGET_DIRECTORY)
+        .help("move all SOURCE arguments into DIRECTORY")
+        .takes_value(true)
+        .value_name("DIRECTORY")
+        .conflicts_with(OPT_NO_TARGET_DIRECTORY)
+    )
+    .arg(
+            Arg::with_name(OPT_NO_TARGET_DIRECTORY)
+            .short("T")
+            .long(OPT_NO_TARGET_DIRECTORY).
+            help("treat DEST as a normal file")
+    )
+    .arg(
+            Arg::with_name(OPT_UPDATE)
+            .short("u")
+            .long(OPT_UPDATE)
+            .help("move only when the SOURCE file is newer than the destination file or when the destination file is missing")
+    )
+    .arg(
+            Arg::with_name(OPT_VERBOSE)
+            .short("v")
+            .long(OPT_VERBOSE).help("explain what is being done")
+    )
+    .arg(
+        Arg::with_name(ARG_FILES)
+            .multiple(true)
+            .takes_value(true)
+            .min_values(2)
+            .required(true)
+        )
+}
+
+fn determine_overwrite_mode(matches: &ArgMatches) -> OverwriteMode {
+    // This does not exactly match the GNU implementation:
+    // The GNU mv defaults to Force, but if more than one of the
+    // overwrite options are supplied, only the last takes effect.
+    // To default to no-clobber in that situation seems safer:
+    //
+    if matches.is_present(OPT_NO_CLOBBER) {
+        OverwriteMode::NoClobber
+    } else if matches.is_present(OPT_INTERACTIVE) {
+        OverwriteMode::Interactive
+    } else {
+        OverwriteMode::Force
+    }
+}
+
+fn exec(files: &[PathBuf], b: Behavior) -> i32 {
+    if let Some(ref name) = b.target_dir {
+        return move_files_into_dir(files, &PathBuf::from(name), &b);
+    }
+    match files.len() {
+        /* case 0/1 are not possible thanks to clap */
+        2 => {
+            let source = &files[0];
+            let target = &files[1];
+            // Here we use the `symlink_metadata()` method instead of `exists()`,
+            // since it handles dangling symlinks correctly. The method gives an
+            // `Ok()` results unless the source does not exist, or the user
+            // lacks permission to access metadata.
+            if source.symlink_metadata().is_err() {
+                show_error!(
+                    "cannot stat '{}': No such file or directory",
+                    source.display()
+                );
+                return 1;
+            }
+
+            if target.is_dir() {
+                if b.no_target_dir {
+                    if !source.is_dir() {
+                        show_error!(
+                            "cannot overwrite directory '{}' with non-directory",
+                            target.display()
+                        );
+                        return 1;
+                    }
+
+                    return match rename(source, target, &b) {
+                        Err(e) => {
+                            show_error!(
+                                "cannot move '{}' to '{}': {}",
+                                source.display(),
+                                target.display(),
+                                e.to_string()
+                            );
+                            1
+                        }
+                        _ => 0,
+                    };
+                }
+
+                return move_files_into_dir(&[source.clone()], target, &b);
+            } else if target.exists() && source.is_dir() {
+                show_error!(
+                    "cannot overwrite non-directory '{}' with directory '{}'",
+                    target.display(),
+                    source.display()
+                );
+                return 1;
+            }
+
+            if let Err(e) = rename(source, target, &b) {
+                show_error!("{}", e);
+                return 1;
+            }
+        }
+        _ => {
+            if b.no_target_dir {
+                show_error!(
+                    "mv: extra operand '{}'\n\
+                     Try '{} --help' for more information.",
+                    files[2].display(),
+                    uucore::execution_phrase()
+                );
+                return 1;
+            }
+            let target_dir = files.last().unwrap();
+            move_files_into_dir(&files[..files.len() - 1], target_dir, &b);
+        }
+    }
+    0
+}
+
+fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i32 {
+    if !target_dir.is_dir() {
+        show_error!("target '{}' is not a directory", target_dir.display());
+        return 1;
+    }
+
+    let mut all_successful = true;
+    for sourcepath in files.iter() {
+        let targetpath = match sourcepath.file_name() {
+            Some(name) => target_dir.join(name),
+            None => {
+                show_error!(
+                    "cannot stat '{}': No such file or directory",
+                    sourcepath.display()
+                );
+
+                all_successful = false;
+                continue;
+            }
+        };
+
+        if let Err(e) = rename(sourcepath, &targetpath, b) {
+            show_error!(
+                "cannot move '{}' to '{}': {}",
+                sourcepath.display(),
+                targetpath.display(),
+                e.to_string()
+            );
+            all_successful = false;
+        }
+    }
+
+    if all_successful {
+        0
+    } else {
+        1
+    }
+}
+
+fn rename(from: &Path, to: &Path, b: &Behavior) -> io::Result<()> {
+    let mut backup_path = None;
+
+    if to.exists() {
+        match b.overwrite {
+            OverwriteMode::NoClobber => return Ok(()),
+            OverwriteMode::Interactive => {
+                println!("{}: overwrite '{}'? ", uucore::util_name(), to.display());
+                if !read_yes() {
+                    return Ok(());
+                }
+            }
+            OverwriteMode::Force => {}
+        };
+
+        backup_path = backup_control::get_backup_path(b.backup, to, &b.suffix);
+        if let Some(ref backup_path) = backup_path {
+            rename_with_fallback(to, backup_path)?;
+        }
+
+        if b.update && fs::metadata(from)?.modified()? <= fs::metadata(to)?.modified()? {
+            return Ok(());
+        }
+    }
+
+    // "to" may no longer exist if it was backed up
+    if to.exists() && to.is_dir() {
+        // normalize behavior between *nix and windows
+        if from.is_dir() {
+            if is_empty_dir(to) {
+                fs::remove_dir(to)?
+            } else {
+                return Err(io::Error::new(io::ErrorKind::Other, "Directory not empty"));
+            }
+        }
+    }
+
+    rename_with_fallback(from, to)?;
+
+    if b.verbose {
+        print!("'{}' -> '{}'", from.display(), to.display());
+        match backup_path {
+            Some(path) => println!(" (backup: '{}')", path.display()),
+            None => println!(),
+        }
+    }
+    Ok(())
+}
+
+/// A wrapper around `fs::rename`, so that if it fails, we try falling back on
+/// copying and removing.
+fn rename_with_fallback(from: &Path, to: &Path) -> io::Result<()> {
+    if fs::rename(from, to).is_err() {
+        // Get metadata without following symlinks
+        let metadata = from.symlink_metadata()?;
+        let file_type = metadata.file_type();
+
+        if file_type.is_symlink() {
+            rename_symlink_fallback(from, to)?;
+        } else if file_type.is_dir() {
+            // We remove the destination directory if it exists to match the
+            // behavior of `fs::rename`. As far as I can tell, `fs_extra`'s
+            // `move_dir` would otherwise behave differently.
+            if to.exists() {
+                fs::remove_dir_all(to)?;
+            }
+            let options = DirCopyOptions {
+                // From the `fs_extra` documentation:
+                // "Recursively copy a directory with a new name or place it
+                // inside the destination. (same behaviors like cp -r in Unix)"
+                copy_inside: true,
+                ..DirCopyOptions::new()
+            };
+            if let Err(err) = move_dir(from, to, &options) {
+                return match err.kind {
+                    fs_extra::error::ErrorKind::PermissionDenied => Err(io::Error::new(
+                        io::ErrorKind::PermissionDenied,
+                        "Permission denied",
+                    )),
+                    _ => Err(io::Error::new(io::ErrorKind::Other, format!("{:?}", err))),
+                };
+            }
+        } else {
+            fs::copy(from, to).and_then(|_| fs::remove_file(from))?;
+        }
+    }
+    Ok(())
+}
+
+/// Move the given symlink to the given destination. On Windows, dangling
+/// symlinks return an error.
+#[inline]
+fn rename_symlink_fallback(from: &Path, to: &Path) -> io::Result<()> {
+    let path_symlink_points_to = fs::read_link(from)?;
+    #[cfg(unix)]
+    {
+        unix::fs::symlink(&path_symlink_points_to, &to).and_then(|_| fs::remove_file(&from))?;
+    }
+    #[cfg(windows)]
+    {
+        if path_symlink_points_to.exists() {
+            if path_symlink_points_to.is_dir() {
+                windows::fs::symlink_dir(&path_symlink_points_to, &to)?;
+            } else {
+                windows::fs::symlink_file(&path_symlink_points_to, &to)?;
+            }
+            fs::remove_file(&from)?;
+        } else {
+            return Err(io::Error::new(
+                io::ErrorKind::NotFound,
+                "can't determine symlink type, since it is dangling",
+            ));
+        }
+    }
+    #[cfg(not(any(windows, unix)))]
+    {
+        return Err(io::Error::new(
+            io::ErrorKind::Other,
+            "your operating system does not support symlinks",
+        ));
+    }
+    Ok(())
+}
+
+fn read_yes() -> bool {
+    let mut s = String::new();
+    match stdin().read_line(&mut s) {
+        Ok(_) => match s.chars().next() {
+            Some(x) => x == 'y' || x == 'Y',
+            _ => false,
+        },
+        _ => false,
+    }
+}
+
+fn is_empty_dir(path: &Path) -> bool {
+    match fs::read_dir(path) {
+        Ok(contents) => contents.peekable().peek().is_none(),
+        Err(_e) => false,
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_nice/nice.rs.html b/src/uu_nice/nice.rs.html new file mode 100644 index 000000000..86787580e --- /dev/null +++ b/src/uu_nice/nice.rs.html @@ -0,0 +1,237 @@ +nice.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) getpriority execvp setpriority nstr PRIO cstrs ENOENT
+
+#[macro_use]
+extern crate uucore;
+
+use libc::{c_char, c_int, execvp, PRIO_PROCESS};
+use std::ffi::CString;
+use std::io::Error;
+use std::ptr;
+
+use clap::{crate_version, App, AppSettings, Arg};
+
+pub mod options {
+    pub static ADJUSTMENT: &str = "adjustment";
+    pub static COMMAND: &str = "COMMAND";
+}
+
+fn usage() -> String {
+    format!(
+        "
+  {0} [OPTIONS] [COMMAND [ARGS]]
+
+Run COMMAND with an adjusted niceness, which affects process scheduling.
+With no COMMAND, print the current niceness.  Niceness values range from at
+least -20 (most favorable to the process) to 19 (least favorable to the
+process).",
+        uucore::execution_phrase()
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mut niceness = unsafe {
+        nix::errno::Errno::clear();
+        libc::getpriority(PRIO_PROCESS, 0)
+    };
+    if Error::last_os_error().raw_os_error().unwrap() != 0 {
+        show_error!("getpriority: {}", Error::last_os_error());
+        return 125;
+    }
+
+    let adjustment = match matches.value_of(options::ADJUSTMENT) {
+        Some(nstr) => {
+            if !matches.is_present(options::COMMAND) {
+                show_error!(
+                    "A command must be given with an adjustment.\nTry '{} --help' for more information.",
+                    uucore::execution_phrase()
+                );
+                return 125;
+            }
+            match nstr.parse() {
+                Ok(num) => num,
+                Err(e) => {
+                    show_error!("\"{}\" is not a valid number: {}", nstr, e);
+                    return 125;
+                }
+            }
+        }
+        None => {
+            if !matches.is_present(options::COMMAND) {
+                println!("{}", niceness);
+                return 0;
+            }
+            10_i32
+        }
+    };
+
+    niceness += adjustment;
+    if unsafe { libc::setpriority(PRIO_PROCESS, 0, niceness) } == -1 {
+        show_warning!("setpriority: {}", Error::last_os_error());
+    }
+
+    let cstrs: Vec<CString> = matches
+        .values_of(options::COMMAND)
+        .unwrap()
+        .map(|x| CString::new(x.as_bytes()).unwrap())
+        .collect();
+
+    let mut args: Vec<*const c_char> = cstrs.iter().map(|s| s.as_ptr()).collect();
+    args.push(ptr::null::<c_char>());
+    unsafe {
+        execvp(args[0], args.as_mut_ptr());
+    }
+
+    show_error!("execvp: {}", Error::last_os_error());
+    if Error::last_os_error().raw_os_error().unwrap() as c_int == libc::ENOENT {
+        127
+    } else {
+        126
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .setting(AppSettings::TrailingVarArg)
+        .version(crate_version!())
+        .arg(
+            Arg::with_name(options::ADJUSTMENT)
+                .short("n")
+                .long(options::ADJUSTMENT)
+                .help("add N to the niceness (default is 10)")
+                .takes_value(true)
+                .allow_hyphen_values(true),
+        )
+        .arg(Arg::with_name(options::COMMAND).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_nl/helper.rs.html b/src/uu_nl/helper.rs.html new file mode 100644 index 000000000..c7015dc83 --- /dev/null +++ b/src/uu_nl/helper.rs.html @@ -0,0 +1,297 @@ +helper.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+
+// spell-checker:ignore (ToDO) conv
+
+use crate::options;
+
+// parse_style parses a style string into a NumberingStyle.
+fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> {
+    if chars.len() == 1 && chars[0] == 'a' {
+        Ok(crate::NumberingStyle::NumberForAll)
+    } else if chars.len() == 1 && chars[0] == 't' {
+        Ok(crate::NumberingStyle::NumberForNonEmpty)
+    } else if chars.len() == 1 && chars[0] == 'n' {
+        Ok(crate::NumberingStyle::NumberForNone)
+    } else if chars.len() > 1 && chars[0] == 'p' {
+        let s: String = chars[1..].iter().cloned().collect();
+        match regex::Regex::new(&s) {
+            Ok(re) => Ok(crate::NumberingStyle::NumberForRegularExpression(Box::new(
+                re,
+            ))),
+            Err(_) => Err(String::from("Illegal regular expression")),
+        }
+    } else {
+        Err(String::from("Illegal style encountered"))
+    }
+}
+
+// parse_options loads the options into the settings, returning an array of
+// error messages.
+pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) -> Vec<String> {
+    // This vector holds error messages encountered.
+    let mut errs: Vec<String> = vec![];
+    settings.renumber = !opts.is_present(options::NO_RENUMBER);
+    match opts.value_of(options::NUMBER_SEPARATOR) {
+        None => {}
+        Some(val) => {
+            settings.number_separator = val.to_owned();
+        }
+    }
+    match opts.value_of(options::NUMBER_FORMAT) {
+        None => {}
+        Some(val) => match val {
+            "ln" => {
+                settings.number_format = crate::NumberFormat::Left;
+            }
+            "rn" => {
+                settings.number_format = crate::NumberFormat::Right;
+            }
+            "rz" => {
+                settings.number_format = crate::NumberFormat::RightZero;
+            }
+            _ => {
+                errs.push(String::from("Illegal value for -n"));
+            }
+        },
+    }
+    match opts.value_of(options::BODY_NUMBERING) {
+        None => {}
+        Some(val) => {
+            let chars: Vec<char> = val.chars().collect();
+            match parse_style(&chars) {
+                Ok(s) => {
+                    settings.body_numbering = s;
+                }
+                Err(message) => {
+                    errs.push(message);
+                }
+            }
+        }
+    }
+    match opts.value_of(options::FOOTER_NUMBERING) {
+        None => {}
+        Some(val) => {
+            let chars: Vec<char> = val.chars().collect();
+            match parse_style(&chars) {
+                Ok(s) => {
+                    settings.footer_numbering = s;
+                }
+                Err(message) => {
+                    errs.push(message);
+                }
+            }
+        }
+    }
+    match opts.value_of(options::HEADER_NUMBERING) {
+        None => {}
+        Some(val) => {
+            let chars: Vec<char> = val.chars().collect();
+            match parse_style(&chars) {
+                Ok(s) => {
+                    settings.header_numbering = s;
+                }
+                Err(message) => {
+                    errs.push(message);
+                }
+            }
+        }
+    }
+    match opts.value_of(options::LINE_INCREMENT) {
+        None => {}
+        Some(val) => {
+            let conv: Option<u64> = val.parse().ok();
+            match conv {
+                None => {
+                    errs.push(String::from("Illegal value for -i"));
+                }
+                Some(num) => settings.line_increment = num,
+            }
+        }
+    }
+    match opts.value_of(options::NUMBER_WIDTH) {
+        None => {}
+        Some(val) => {
+            let conv: Option<usize> = val.parse().ok();
+            match conv {
+                None => {
+                    errs.push(String::from("Illegal value for -w"));
+                }
+                Some(num) => settings.number_width = num,
+            }
+        }
+    }
+    match opts.value_of(options::STARTING_LINE_NUMBER) {
+        None => {}
+        Some(val) => {
+            let conv: Option<u64> = val.parse().ok();
+            match conv {
+                None => {
+                    errs.push(String::from("Illegal value for -v"));
+                }
+                Some(num) => settings.starting_line_number = num,
+            }
+        }
+    }
+    match opts.value_of(options::JOIN_BLANK_LINES) {
+        None => {}
+        Some(val) => {
+            let conv: Option<u64> = val.parse().ok();
+            match conv {
+                None => {
+                    errs.push(String::from("Illegal value for -l"));
+                }
+                Some(num) => settings.join_blank_lines = num,
+            }
+        }
+    }
+    errs
+}
+
+
\ No newline at end of file diff --git a/src/uu_nl/nl.rs.html b/src/uu_nl/nl.rs.html new file mode 100644 index 000000000..c91992cff --- /dev/null +++ b/src/uu_nl/nl.rs.html @@ -0,0 +1,787 @@ +nl.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Tobias Bohumir Schottdorf <tobias.schottdorf@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+//  *
+
+// spell-checker:ignore (ToDO) corasick memchr
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{stdin, BufRead, BufReader, Read};
+use std::iter::repeat;
+use std::path::Path;
+use uucore::InvalidEncodingHandling;
+
+mod helper;
+
+static NAME: &str = "nl";
+static USAGE: &str = "nl [OPTION]... [FILE]...";
+// A regular expression matching everything.
+
+// Settings store options used by nl to produce its output.
+pub struct Settings {
+    // The variables corresponding to the options -h, -b, and -f.
+    header_numbering: NumberingStyle,
+    body_numbering: NumberingStyle,
+    footer_numbering: NumberingStyle,
+    // The variable corresponding to -d
+    section_delimiter: [char; 2],
+    // The variables corresponding to the options -v, -i, -l, -w.
+    starting_line_number: u64,
+    line_increment: u64,
+    join_blank_lines: u64,
+    number_width: usize, // Used with String::from_char, hence usize.
+    // The format of the number and the (default value for)
+    // renumbering each page.
+    number_format: NumberFormat,
+    renumber: bool,
+    // The string appended to each line number output.
+    number_separator: String,
+}
+
+// NumberingStyle stores which lines are to be numbered.
+// The possible options are:
+// 1. Number all lines
+// 2. Number only nonempty lines
+// 3. Don't number any lines at all
+// 4. Number all lines that match a basic regular expression.
+#[allow(clippy::enum_variant_names)]
+enum NumberingStyle {
+    NumberForAll,
+    NumberForNonEmpty,
+    NumberForNone,
+    NumberForRegularExpression(Box<regex::Regex>),
+}
+
+// NumberFormat specifies how line numbers are output within their allocated
+// space. They are justified to the left or right, in the latter case with
+// the option of having all unused space to its left turned into leading zeroes.
+enum NumberFormat {
+    Left,
+    Right,
+    RightZero,
+}
+
+pub mod options {
+    pub const FILE: &str = "file";
+    pub const BODY_NUMBERING: &str = "body-numbering";
+    pub const SECTION_DELIMITER: &str = "section-delimiter";
+    pub const FOOTER_NUMBERING: &str = "footer-numbering";
+    pub const HEADER_NUMBERING: &str = "header-numbering";
+    pub const LINE_INCREMENT: &str = "line-increment";
+    pub const JOIN_BLANK_LINES: &str = "join-blank-lines";
+    pub const NUMBER_FORMAT: &str = "number-format";
+    pub const NO_RENUMBER: &str = "no-renumber";
+    pub const NUMBER_SEPARATOR: &str = "number-separator";
+    pub const STARTING_LINE_NUMBER: &str = "starting-line-number";
+    pub const NUMBER_WIDTH: &str = "number-width";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    // A mutable settings object, initialized with the defaults.
+    let mut settings = Settings {
+        header_numbering: NumberingStyle::NumberForNone,
+        body_numbering: NumberingStyle::NumberForAll,
+        footer_numbering: NumberingStyle::NumberForNone,
+        section_delimiter: ['\\', ':'],
+        starting_line_number: 1,
+        line_increment: 1,
+        join_blank_lines: 1,
+        number_width: 6,
+        number_format: NumberFormat::Right,
+        renumber: true,
+        number_separator: String::from("\t"),
+    };
+
+    // Update the settings from the command line options, and terminate the
+    // program if some options could not successfully be parsed.
+    let parse_errors = helper::parse_options(&mut settings, &matches);
+    if !parse_errors.is_empty() {
+        show_error!("Invalid arguments supplied.");
+        for message in &parse_errors {
+            println!("{}", message);
+        }
+        return 1;
+    }
+
+    let mut read_stdin = false;
+    let files: Vec<String> = match matches.values_of(options::FILE) {
+        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
+        None => vec!["-".to_owned()],
+    };
+
+    for file in &files {
+        if file == "-" {
+            // If both file names and '-' are specified, we choose to treat first all
+            // regular files, and then read from stdin last.
+            read_stdin = true;
+            continue;
+        }
+        let path = Path::new(file);
+        let reader = File::open(path).unwrap();
+        let mut buffer = BufReader::new(reader);
+        nl(&mut buffer, &settings);
+    }
+
+    if read_stdin {
+        let mut buffer = BufReader::new(stdin());
+        nl(&mut buffer, &settings);
+    }
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(USAGE)
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+        .arg(
+            Arg::with_name(options::BODY_NUMBERING)
+                .short("b")
+                .long(options::BODY_NUMBERING)
+                .help("use STYLE for numbering body lines")
+                .value_name("SYNTAX"),
+        )
+        .arg(
+            Arg::with_name(options::SECTION_DELIMITER)
+                .short("d")
+                .long(options::SECTION_DELIMITER)
+                .help("use CC for separating logical pages")
+                .value_name("CC"),
+        )
+        .arg(
+            Arg::with_name(options::FOOTER_NUMBERING)
+                .short("f")
+                .long(options::FOOTER_NUMBERING)
+                .help("use STYLE for numbering footer lines")
+                .value_name("STYLE"),
+        )
+        .arg(
+            Arg::with_name(options::HEADER_NUMBERING)
+                .short("h")
+                .long(options::HEADER_NUMBERING)
+                .help("use STYLE for numbering header lines")
+                .value_name("STYLE"),
+        )
+        .arg(
+            Arg::with_name(options::LINE_INCREMENT)
+                .short("i")
+                .long(options::LINE_INCREMENT)
+                .help("line number increment at each line")
+                .value_name("NUMBER"),
+        )
+        .arg(
+            Arg::with_name(options::JOIN_BLANK_LINES)
+                .short("l")
+                .long(options::JOIN_BLANK_LINES)
+                .help("group of NUMBER empty lines counted as one")
+                .value_name("NUMBER"),
+        )
+        .arg(
+            Arg::with_name(options::NUMBER_FORMAT)
+                .short("n")
+                .long(options::NUMBER_FORMAT)
+                .help("insert line numbers according to FORMAT")
+                .value_name("FORMAT"),
+        )
+        .arg(
+            Arg::with_name(options::NO_RENUMBER)
+                .short("p")
+                .long(options::NO_RENUMBER)
+                .help("do not reset line numbers at logical pages"),
+        )
+        .arg(
+            Arg::with_name(options::NUMBER_SEPARATOR)
+                .short("s")
+                .long(options::NUMBER_SEPARATOR)
+                .help("add STRING after (possible) line number")
+                .value_name("STRING"),
+        )
+        .arg(
+            Arg::with_name(options::STARTING_LINE_NUMBER)
+                .short("v")
+                .long(options::STARTING_LINE_NUMBER)
+                .help("first line number on each logical page")
+                .value_name("NUMBER"),
+        )
+        .arg(
+            Arg::with_name(options::NUMBER_WIDTH)
+                .short("w")
+                .long(options::NUMBER_WIDTH)
+                .help("use NUMBER columns for line numbers")
+                .value_name("NUMBER"),
+        )
+}
+
+// nl implements the main functionality for an individual buffer.
+fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) {
+    let regexp: regex::Regex = regex::Regex::new(r".?").unwrap();
+    let mut line_no = settings.starting_line_number;
+    // The current line number's width as a string. Using to_string is inefficient
+    // but since we only do it once, it should not hurt.
+    let mut line_no_width = line_no.to_string().len();
+    let line_no_width_initial = line_no_width;
+    // Stores the smallest integer with one more digit than line_no, so that
+    // when line_no >= line_no_threshold, we need to use one more digit.
+    let mut line_no_threshold = 10u64.pow(line_no_width as u32);
+    let mut empty_line_count: u64 = 0;
+    let fill_char = match settings.number_format {
+        NumberFormat::RightZero => '0',
+        _ => ' ',
+    };
+    // Initially, we use the body's line counting settings
+    let mut regex_filter = match settings.body_numbering {
+        NumberingStyle::NumberForRegularExpression(ref re) => re,
+        _ => &regexp,
+    };
+    let mut line_filter: fn(&str, &regex::Regex) -> bool = pass_regex;
+    for mut l in reader.lines().map(|r| r.unwrap()) {
+        // Sanitize the string. We want to print the newline ourselves.
+        if l.ends_with('\n') {
+            l.pop();
+        }
+        // Next we iterate through the individual chars to see if this
+        // is one of the special lines starting a new "section" in the
+        // document.
+        let line = l;
+        let mut odd = false;
+        // matched_group counts how many copies of section_delimiter
+        // this string consists of (0 if there's anything else)
+        let mut matched_groups = 0u8;
+        for c in line.chars() {
+            // If this is a newline character, the loop should end.
+            if c == '\n' {
+                break;
+            }
+            // If we have already seen three groups (corresponding to
+            // a header) or the current char does not form part of
+            // a new group, then this line is not a segment indicator.
+            if matched_groups >= 3 || settings.section_delimiter[if odd { 1 } else { 0 }] != c {
+                matched_groups = 0;
+                break;
+            }
+            if odd {
+                // We have seen a new group and count it.
+                matched_groups += 1;
+            }
+            odd = !odd;
+        }
+
+        // See how many groups we matched. That will tell us if this is
+        // a line starting a new segment, and the number of groups
+        // indicates what type of segment.
+        if matched_groups > 0 {
+            // The current line is a section delimiter, so we output
+            // a blank line.
+            println!();
+            // However the line does not count as a blank line, so we
+            // reset the counter used for --join-blank-lines.
+            empty_line_count = 0;
+            match *match matched_groups {
+                3 => {
+                    // This is a header, so we may need to reset the
+                    // line number and the line width
+                    if settings.renumber {
+                        line_no = settings.starting_line_number;
+                        line_no_width = line_no_width_initial;
+                        line_no_threshold = 10u64.pow(line_no_width as u32);
+                    }
+                    &settings.header_numbering
+                }
+                1 => &settings.footer_numbering,
+                // The only option left is 2, but rust wants
+                // a catch-all here.
+                _ => &settings.body_numbering,
+            } {
+                NumberingStyle::NumberForAll => {
+                    line_filter = pass_all;
+                }
+                NumberingStyle::NumberForNonEmpty => {
+                    line_filter = pass_nonempty;
+                }
+                NumberingStyle::NumberForNone => {
+                    line_filter = pass_none;
+                }
+                NumberingStyle::NumberForRegularExpression(ref re) => {
+                    line_filter = pass_regex;
+                    regex_filter = re;
+                }
+            }
+            continue;
+        }
+        // From this point on we format and print a "regular" line.
+        if line.is_empty() {
+            // The line is empty, which means that we have to care
+            // about the --join-blank-lines parameter.
+            empty_line_count += 1;
+        } else {
+            // This saves us from having to check for an empty string
+            // in the next selector.
+            empty_line_count = 0;
+        }
+        if !line_filter(&line, regex_filter)
+            || (empty_line_count > 0 && empty_line_count < settings.join_blank_lines)
+        {
+            // No number is printed for this line. Either we did not
+            // want to print one in the first place, or it is a blank
+            // line but we are still collecting more blank lines via
+            // the option --join-blank-lines.
+            println!("{}", line);
+            continue;
+        }
+        // If we make it here, then either we are printing a non-empty
+        // line or assigning a line number to an empty line. Either
+        // way, start counting empties from zero once more.
+        empty_line_count = 0;
+        // A line number is to be printed.
+        let w = if settings.number_width > line_no_width {
+            settings.number_width - line_no_width
+        } else {
+            0
+        };
+        let fill: String = repeat(fill_char).take(w).collect();
+        match settings.number_format {
+            NumberFormat::Left => println!(
+                "{1}{0}{2}{3}",
+                fill, line_no, settings.number_separator, line
+            ),
+            _ => println!(
+                "{0}{1}{2}{3}",
+                fill, line_no, settings.number_separator, line
+            ),
+        }
+        // Now update the variables for the (potential) next
+        // line.
+        line_no += settings.line_increment;
+        while line_no >= line_no_threshold {
+            // The line number just got longer.
+            line_no_threshold *= 10;
+            line_no_width += 1;
+        }
+    }
+}
+
+fn pass_regex(line: &str, re: &regex::Regex) -> bool {
+    re.is_match(line)
+}
+
+fn pass_nonempty(line: &str, _: &regex::Regex) -> bool {
+    !line.is_empty()
+}
+
+fn pass_none(_: &str, _: &regex::Regex) -> bool {
+    false
+}
+
+fn pass_all(_: &str, _: &regex::Regex) -> bool {
+    true
+}
+
+
\ No newline at end of file diff --git a/src/uu_nohup/nohup.rs.html b/src/uu_nohup/nohup.rs.html new file mode 100644 index 000000000..c5e4eb551 --- /dev/null +++ b/src/uu_nohup/nohup.rs.html @@ -0,0 +1,353 @@ +nohup.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) 2014 Vsevolod Velichko <torkvemada@sorokdva.net>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) execvp SIGHUP cproc vprocmgr cstrs homeout
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, AppSettings, Arg};
+use libc::{c_char, dup2, execvp, signal};
+use libc::{SIGHUP, SIG_IGN};
+use std::env;
+use std::ffi::CString;
+use std::fs::{File, OpenOptions};
+use std::io::Error;
+use std::os::unix::prelude::*;
+use std::path::{Path, PathBuf};
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Run COMMAND ignoring hangup signals.";
+static LONG_HELP: &str = "
+If standard input is terminal, it'll be replaced with /dev/null.
+If standard output is terminal, it'll be appended to nohup.out instead,
+or $HOME/nohup.out, if nohup.out open failed.
+If standard error is terminal, it'll be redirected to stdout.
+";
+static NOHUP_OUT: &str = "nohup.out";
+// exit codes that match the GNU implementation
+static EXIT_CANCELED: i32 = 125;
+static EXIT_CANNOT_INVOKE: i32 = 126;
+static EXIT_ENOENT: i32 = 127;
+static POSIX_NOHUP_FAILURE: i32 = 127;
+
+mod options {
+    pub const CMD: &str = "cmd";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    replace_fds();
+
+    unsafe { signal(SIGHUP, SIG_IGN) };
+
+    if unsafe { !_vprocmgr_detach_from_console(0).is_null() } {
+        crash!(2, "Cannot detach from console")
+    };
+
+    let cstrs: Vec<CString> = matches
+        .values_of(options::CMD)
+        .unwrap()
+        .map(|x| CString::new(x.as_bytes()).unwrap())
+        .collect();
+    let mut args: Vec<*const c_char> = cstrs.iter().map(|s| s.as_ptr()).collect();
+    args.push(std::ptr::null());
+
+    let ret = unsafe { execvp(args[0], args.as_mut_ptr()) };
+    match ret {
+        libc::ENOENT => EXIT_ENOENT,
+        _ => EXIT_CANNOT_INVOKE,
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::CMD)
+                .hidden(true)
+                .required(true)
+                .multiple(true),
+        )
+        .setting(AppSettings::TrailingVarArg)
+}
+
+fn replace_fds() {
+    if atty::is(atty::Stream::Stdin) {
+        let new_stdin = match File::open(Path::new("/dev/null")) {
+            Ok(t) => t,
+            Err(e) => crash!(2, "Cannot replace STDIN: {}", e),
+        };
+        if unsafe { dup2(new_stdin.as_raw_fd(), 0) } != 0 {
+            crash!(2, "Cannot replace STDIN: {}", Error::last_os_error())
+        }
+    }
+
+    if atty::is(atty::Stream::Stdout) {
+        let new_stdout = find_stdout();
+        let fd = new_stdout.as_raw_fd();
+
+        if unsafe { dup2(fd, 1) } != 1 {
+            crash!(2, "Cannot replace STDOUT: {}", Error::last_os_error())
+        }
+    }
+
+    if atty::is(atty::Stream::Stderr) && unsafe { dup2(1, 2) } != 2 {
+        crash!(2, "Cannot replace STDERR: {}", Error::last_os_error())
+    }
+}
+
+fn find_stdout() -> File {
+    let internal_failure_code = match std::env::var("POSIXLY_CORRECT") {
+        Ok(_) => POSIX_NOHUP_FAILURE,
+        Err(_) => EXIT_CANCELED,
+    };
+
+    match OpenOptions::new()
+        .write(true)
+        .create(true)
+        .append(true)
+        .open(Path::new(NOHUP_OUT))
+    {
+        Ok(t) => {
+            show_error!("ignoring input and appending output to '{}'", NOHUP_OUT);
+            t
+        }
+        Err(e1) => {
+            let home = match env::var("HOME") {
+                Err(_) => {
+                    show_error!("failed to open '{}': {}", NOHUP_OUT, e1);
+                    exit!(internal_failure_code)
+                }
+                Ok(h) => h,
+            };
+            let mut homeout = PathBuf::from(home);
+            homeout.push(NOHUP_OUT);
+            let homeout_str = homeout.to_str().unwrap();
+            match OpenOptions::new()
+                .write(true)
+                .create(true)
+                .append(true)
+                .open(&homeout)
+            {
+                Ok(t) => {
+                    show_error!("ignoring input and appending output to '{}'", homeout_str);
+                    t
+                }
+                Err(e2) => {
+                    show_error!("failed to open '{}': {}", NOHUP_OUT, e1);
+                    show_error!("failed to open '{}': {}", homeout_str, e2);
+                    exit!(internal_failure_code)
+                }
+            }
+        }
+    }
+}
+
+fn usage() -> String {
+    format!(
+        "{0} COMMAND [ARG]...\n    {0} FLAG",
+        uucore::execution_phrase()
+    )
+}
+
+#[cfg(target_vendor = "apple")]
+extern "C" {
+    fn _vprocmgr_detach_from_console(flags: u32) -> *const libc::c_int;
+}
+
+#[cfg(any(target_os = "linux", target_os = "freebsd"))]
+unsafe fn _vprocmgr_detach_from_console(_: u32) -> *const libc::c_int {
+    std::ptr::null()
+}
+
+
\ No newline at end of file diff --git a/src/uu_nproc/nproc.rs.html b/src/uu_nproc/nproc.rs.html new file mode 100644 index 000000000..829f74cad --- /dev/null +++ b/src/uu_nproc/nproc.rs.html @@ -0,0 +1,243 @@ +nproc.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Gehring <mg@ebfe.org>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) NPROCESSORS nprocs numstr threadstr sysconf
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::env;
+
+#[cfg(target_os = "linux")]
+pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
+#[cfg(target_vendor = "apple")]
+pub const _SC_NPROCESSORS_CONF: libc::c_int = libc::_SC_NPROCESSORS_CONF;
+#[cfg(target_os = "freebsd")]
+pub const _SC_NPROCESSORS_CONF: libc::c_int = 57;
+#[cfg(target_os = "netbsd")]
+pub const _SC_NPROCESSORS_CONF: libc::c_int = 1001;
+
+static OPT_ALL: &str = "all";
+static OPT_IGNORE: &str = "ignore";
+
+static ABOUT: &str = "Print the number of cores available to the current process.";
+
+fn usage() -> String {
+    format!("{0} [OPTIONS]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mut ignore = match matches.value_of(OPT_IGNORE) {
+        Some(numstr) => match numstr.parse() {
+            Ok(num) => num,
+            Err(e) => {
+                show_error!("\"{}\" is not a valid number: {}", numstr, e);
+                return 1;
+            }
+        },
+        None => 0,
+    };
+
+    if !matches.is_present(OPT_ALL) {
+        // OMP_NUM_THREADS doesn't have an impact on --all
+        ignore += match env::var("OMP_NUM_THREADS") {
+            Ok(threadstr) => threadstr.parse().unwrap_or(0),
+            Err(_) => 0,
+        };
+    }
+
+    let mut cores = if matches.is_present(OPT_ALL) {
+        num_cpus_all()
+    } else {
+        num_cpus::get()
+    };
+
+    if cores <= ignore {
+        cores = 1;
+    } else {
+        cores -= ignore;
+    }
+    println!("{}", cores);
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_ALL)
+                .short("")
+                .long(OPT_ALL)
+                .help("print the number of cores available to the system"),
+        )
+        .arg(
+            Arg::with_name(OPT_IGNORE)
+                .short("")
+                .long(OPT_IGNORE)
+                .takes_value(true)
+                .help("ignore up to N cores"),
+        )
+}
+
+#[cfg(any(
+    target_os = "linux",
+    target_vendor = "apple",
+    target_os = "freebsd",
+    target_os = "netbsd"
+))]
+fn num_cpus_all() -> usize {
+    let nprocs = unsafe { libc::sysconf(_SC_NPROCESSORS_CONF) };
+    if nprocs == 1 {
+        // In some situation, /proc and /sys are not mounted, and sysconf returns 1.
+        // However, we want to guarantee that `nproc --all` >= `nproc`.
+        num_cpus::get()
+    } else if nprocs > 0 {
+        nprocs as usize
+    } else {
+        1
+    }
+}
+
+// Other platforms (e.g., windows), num_cpus::get() directly.
+#[cfg(not(any(
+    target_os = "linux",
+    target_vendor = "apple",
+    target_os = "freebsd",
+    target_os = "netbsd"
+)))]
+fn num_cpus_all() -> usize {
+    num_cpus::get()
+}
+
+
\ No newline at end of file diff --git a/src/uu_numfmt/format.rs.html b/src/uu_numfmt/format.rs.html new file mode 100644 index 000000000..9026604dd --- /dev/null +++ b/src/uu_numfmt/format.rs.html @@ -0,0 +1,607 @@ +format.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+
+use crate::options::{NumfmtOptions, RoundMethod};
+use crate::units::{DisplayableSuffix, RawSuffix, Result, Suffix, Unit, IEC_BASES, SI_BASES};
+
+/// Iterate over a line's fields, where each field is a contiguous sequence of
+/// non-whitespace, optionally prefixed with one or more characters of leading
+/// whitespace. Fields are returned as tuples of `(prefix, field)`.
+///
+/// # Examples:
+///
+/// ```
+/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("    1234 5") };
+///
+/// assert_eq!(Some(("    ", "1234")), fields.next());
+/// assert_eq!(Some((" ", "5")), fields.next());
+/// assert_eq!(None, fields.next());
+/// ```
+///
+/// Delimiters are included in the results; `prefix` will be empty only for
+/// the first field of the line (including the case where the input line is
+/// empty):
+///
+/// ```
+/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
+///
+/// assert_eq!(Some(("", "first")), fields.next());
+/// assert_eq!(Some((" ", "second")), fields.next());
+///
+/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
+///
+/// assert_eq!(Some(("", "")), fields.next());
+/// ```
+pub struct WhitespaceSplitter<'a> {
+    pub s: Option<&'a str>,
+}
+
+impl<'a> Iterator for WhitespaceSplitter<'a> {
+    type Item = (&'a str, &'a str);
+
+    /// Yield the next field in the input string as a tuple `(prefix, field)`.
+    fn next(&mut self) -> Option<Self::Item> {
+        let haystack = self.s?;
+
+        let (prefix, field) = haystack.split_at(
+            haystack
+                .find(|c: char| !c.is_whitespace())
+                .unwrap_or_else(|| haystack.len()),
+        );
+
+        let (field, rest) = field.split_at(
+            field
+                .find(|c: char| c.is_whitespace())
+                .unwrap_or_else(|| field.len()),
+        );
+
+        self.s = if !rest.is_empty() { Some(rest) } else { None };
+
+        Some((prefix, field))
+    }
+}
+
+fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
+    if s.is_empty() {
+        return Err("invalid number: ''".to_string());
+    }
+
+    let with_i = s.ends_with('i');
+    let mut iter = s.chars();
+    if with_i {
+        iter.next_back();
+    }
+    let suffix = match iter.next_back() {
+        Some('K') => Some((RawSuffix::K, with_i)),
+        Some('M') => Some((RawSuffix::M, with_i)),
+        Some('G') => Some((RawSuffix::G, with_i)),
+        Some('T') => Some((RawSuffix::T, with_i)),
+        Some('P') => Some((RawSuffix::P, with_i)),
+        Some('E') => Some((RawSuffix::E, with_i)),
+        Some('Z') => Some((RawSuffix::Z, with_i)),
+        Some('Y') => Some((RawSuffix::Y, with_i)),
+        Some('0'..='9') => None,
+        _ => return Err(format!("invalid suffix in input: '{}'", s)),
+    };
+
+    let suffix_len = match suffix {
+        None => 0,
+        Some((_, false)) => 1,
+        Some((_, true)) => 2,
+    };
+
+    let number = s[..s.len() - suffix_len]
+        .parse::<f64>()
+        .map_err(|_| format!("invalid number: '{}'", s))?;
+
+    Ok((number, suffix))
+}
+
+fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
+    match (s, u) {
+        (None, _) => Ok(i),
+        (Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
+            match raw_suffix {
+                RawSuffix::K => Ok(i * 1e3),
+                RawSuffix::M => Ok(i * 1e6),
+                RawSuffix::G => Ok(i * 1e9),
+                RawSuffix::T => Ok(i * 1e12),
+                RawSuffix::P => Ok(i * 1e15),
+                RawSuffix::E => Ok(i * 1e18),
+                RawSuffix::Z => Ok(i * 1e21),
+                RawSuffix::Y => Ok(i * 1e24),
+            }
+        }
+        (Some((raw_suffix, false)), &Unit::Iec(false))
+        | (Some((raw_suffix, true)), &Unit::Auto)
+        | (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
+            RawSuffix::K => Ok(i * IEC_BASES[1]),
+            RawSuffix::M => Ok(i * IEC_BASES[2]),
+            RawSuffix::G => Ok(i * IEC_BASES[3]),
+            RawSuffix::T => Ok(i * IEC_BASES[4]),
+            RawSuffix::P => Ok(i * IEC_BASES[5]),
+            RawSuffix::E => Ok(i * IEC_BASES[6]),
+            RawSuffix::Z => Ok(i * IEC_BASES[7]),
+            RawSuffix::Y => Ok(i * IEC_BASES[8]),
+        },
+        (_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
+    }
+}
+
+fn transform_from(s: &str, opts: &Unit) -> Result<f64> {
+    let (i, suffix) = parse_suffix(s)?;
+
+    remove_suffix(i, suffix, opts).map(|n| if n < 0.0 { -n.abs().ceil() } else { n.ceil() })
+}
+
+/// Divide numerator by denominator, with rounding.
+///
+/// If the result of the division is less than 10.0, round to one decimal point.
+///
+/// Otherwise, round to an integer.
+///
+/// # Examples:
+///
+/// ```
+/// use uu_numfmt::format::div_round;
+/// use uu_numfmt::options::RoundMethod;
+///
+/// // Rounding methods:
+/// assert_eq!(div_round(1.01, 1.0, RoundMethod::FromZero), 1.1);
+/// assert_eq!(div_round(1.01, 1.0, RoundMethod::TowardsZero), 1.0);
+/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Up), 1.1);
+/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Down), 1.0);
+/// assert_eq!(div_round(1.01, 1.0, RoundMethod::Nearest), 1.0);
+///
+/// // Division:
+/// assert_eq!(div_round(999.1, 1000.0, RoundMethod::FromZero), 1.0);
+/// assert_eq!(div_round(1001., 10., RoundMethod::FromZero), 101.);
+/// assert_eq!(div_round(9991., 10., RoundMethod::FromZero), 1000.);
+/// assert_eq!(div_round(-12.34, 1.0, RoundMethod::FromZero), -13.0);
+/// assert_eq!(div_round(1000.0, -3.14, RoundMethod::FromZero), -319.0);
+/// assert_eq!(div_round(-271828.0, -271.0, RoundMethod::FromZero), 1004.0);
+/// ```
+pub fn div_round(n: f64, d: f64, method: RoundMethod) -> f64 {
+    let v = n / d;
+
+    if v.abs() < 10.0 {
+        method.round(10.0 * v) / 10.0
+    } else {
+        method.round(v)
+    }
+}
+
+fn consider_suffix(n: f64, u: &Unit, round_method: RoundMethod) -> Result<(f64, Option<Suffix>)> {
+    use crate::units::RawSuffix::*;
+
+    let abs_n = n.abs();
+    let suffixes = [K, M, G, T, P, E, Z, Y];
+
+    let (bases, with_i) = match *u {
+        Unit::Si => (&SI_BASES, false),
+        Unit::Iec(with_i) => (&IEC_BASES, with_i),
+        Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
+        Unit::None => return Ok((n, None)),
+    };
+
+    let i = match abs_n {
+        _ if abs_n <= bases[1] - 1.0 => return Ok((n, None)),
+        _ if abs_n < bases[2] => 1,
+        _ if abs_n < bases[3] => 2,
+        _ if abs_n < bases[4] => 3,
+        _ if abs_n < bases[5] => 4,
+        _ if abs_n < bases[6] => 5,
+        _ if abs_n < bases[7] => 6,
+        _ if abs_n < bases[8] => 7,
+        _ if abs_n < bases[9] => 8,
+        _ => return Err("Number is too big and unsupported".to_string()),
+    };
+
+    let v = div_round(n, bases[i], round_method);
+
+    // check if rounding pushed us into the next base
+    if v.abs() >= bases[1] {
+        Ok((v / bases[1], Some((suffixes[i], with_i))))
+    } else {
+        Ok((v, Some((suffixes[i - 1], with_i))))
+    }
+}
+
+fn transform_to(s: f64, opts: &Unit, round_method: RoundMethod) -> Result<String> {
+    let (i2, s) = consider_suffix(s, opts, round_method)?;
+    Ok(match s {
+        None => format!("{}", i2),
+        Some(s) if i2.abs() < 10.0 => format!("{:.1}{}", i2, DisplayableSuffix(s)),
+        Some(s) => format!("{:.0}{}", i2, DisplayableSuffix(s)),
+    })
+}
+
+fn format_string(
+    source: &str,
+    options: &NumfmtOptions,
+    implicit_padding: Option<isize>,
+) -> Result<String> {
+    let number = transform_to(
+        transform_from(source, &options.transform.from)?,
+        &options.transform.to,
+        options.round,
+    )?;
+
+    Ok(match implicit_padding.unwrap_or(options.padding) {
+        0 => number,
+        p if p > 0 => format!("{:>padding$}", number, padding = p as usize),
+        p => format!("{:<padding$}", number, padding = p.abs() as usize),
+    })
+}
+
+fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
+    let delimiter = options.delimiter.as_ref().unwrap();
+
+    for (n, field) in (1..).zip(s.split(delimiter)) {
+        let field_selected = uucore::ranges::contain(&options.fields, n);
+
+        // print delimiter before second and subsequent fields
+        if n > 1 {
+            print!("{}", delimiter);
+        }
+
+        if field_selected {
+            print!("{}", format_string(field.trim_start(), options, None)?);
+        } else {
+            // print unselected field without conversion
+            print!("{}", field);
+        }
+    }
+
+    println!();
+
+    Ok(())
+}
+
+fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
+    for (n, (prefix, field)) in (1..).zip(WhitespaceSplitter { s: Some(s) }) {
+        let field_selected = uucore::ranges::contain(&options.fields, n);
+
+        if field_selected {
+            let empty_prefix = prefix.is_empty();
+
+            // print delimiter before second and subsequent fields
+            let prefix = if n > 1 {
+                print!(" ");
+                &prefix[1..]
+            } else {
+                &prefix
+            };
+
+            let implicit_padding = if !empty_prefix && options.padding == 0 {
+                Some((prefix.len() + field.len()) as isize)
+            } else {
+                None
+            };
+
+            print!("{}", format_string(field, options, implicit_padding)?);
+        } else {
+            // print unselected field without conversion
+            print!("{}{}", prefix, field);
+        }
+    }
+
+    println!();
+
+    Ok(())
+}
+
+/// Format a line of text according to the selected options.
+///
+/// Given a line of text `s`, split the line into fields, transform and format
+/// any selected numeric fields, and print the result to stdout. Fields not
+/// selected for conversion are passed through unmodified.
+pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
+    match &options.delimiter {
+        Some(_) => format_and_print_delimited(s, options),
+        None => format_and_print_whitespace(s, options),
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_numfmt/numfmt.rs.html b/src/uu_numfmt/numfmt.rs.html new file mode 100644 index 000000000..3f5bf6011 --- /dev/null +++ b/src/uu_numfmt/numfmt.rs.html @@ -0,0 +1,495 @@ +numfmt.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Yury Krivopalov <ykrivopalov@yandex.ru>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore N'th M'th
+
+#[macro_use]
+extern crate uucore;
+
+use crate::format::format_and_print;
+use crate::options::*;
+use crate::units::{Result, Unit};
+use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
+use std::io::{BufRead, Write};
+use uucore::ranges::Range;
+
+pub mod format;
+pub mod options;
+mod units;
+
+static ABOUT: &str = "Convert numbers from/to human-readable strings";
+static LONG_HELP: &str = "UNIT options:
+   none   no auto-scaling is done; suffixes will trigger an error
+
+   auto   accept optional single/two letter suffix:
+
+          1K = 1000, 1Ki = 1024, 1M = 1000000, 1Mi = 1048576,
+
+   si     accept optional single letter suffix:
+
+          1K = 1000, 1M = 1000000, ...
+
+   iec    accept optional single letter suffix:
+
+          1K = 1024, 1M = 1048576, ...
+
+   iec-i  accept optional two-letter suffix:
+
+          1Ki = 1024, 1Mi = 1048576, ...
+
+FIELDS supports cut(1) style field ranges:
+  N    N'th field, counted from 1
+  N-   from N'th field, to end of line
+  N-M  from N'th to M'th field (inclusive)
+  -M   from first to M'th field (inclusive)
+  -    all fields
+Multiple fields/ranges can be separated with commas
+";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [NUMBER]...", uucore::execution_phrase())
+}
+
+fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: NumfmtOptions) -> Result<()> {
+    for l in args {
+        format_and_print(l, &options)?;
+    }
+
+    Ok(())
+}
+
+fn handle_stdin(options: NumfmtOptions) -> Result<()> {
+    let stdin = std::io::stdin();
+    let locked_stdin = stdin.lock();
+
+    let mut lines = locked_stdin.lines();
+    for l in lines.by_ref().take(options.header) {
+        l.map(|s| println!("{}", s)).map_err(|e| e.to_string())?;
+    }
+
+    for l in lines {
+        l.map_err(|e| e.to_string())
+            .and_then(|l| format_and_print(&l, &options))?;
+    }
+
+    Ok(())
+}
+
+fn parse_unit(s: &str) -> Result<Unit> {
+    match s {
+        "auto" => Ok(Unit::Auto),
+        "si" => Ok(Unit::Si),
+        "iec" => Ok(Unit::Iec(false)),
+        "iec-i" => Ok(Unit::Iec(true)),
+        "none" => Ok(Unit::None),
+        _ => Err("Unsupported unit is specified".to_owned()),
+    }
+}
+
+fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
+    let from = parse_unit(args.value_of(options::FROM).unwrap())?;
+    let to = parse_unit(args.value_of(options::TO).unwrap())?;
+
+    let transform = TransformOptions { from, to };
+
+    let padding = match args.value_of(options::PADDING) {
+        Some(s) => s.parse::<isize>().map_err(|err| err.to_string()),
+        None => Ok(0),
+    }?;
+
+    let header = match args.occurrences_of(options::HEADER) {
+        0 => Ok(0),
+        _ => {
+            let value = args.value_of(options::HEADER).unwrap();
+
+            value
+                .parse::<usize>()
+                .map_err(|_| value)
+                .and_then(|n| match n {
+                    0 => Err(value),
+                    _ => Ok(n),
+                })
+                .map_err(|value| format!("invalid header value '{}'", value))
+        }
+    }?;
+
+    let fields = match args.value_of(options::FIELD).unwrap() {
+        "-" => vec![Range {
+            low: 1,
+            high: std::usize::MAX,
+        }],
+        v => Range::from_list(v)?,
+    };
+
+    let delimiter = args.value_of(options::DELIMITER).map_or(Ok(None), |arg| {
+        if arg.len() == 1 {
+            Ok(Some(arg.to_string()))
+        } else {
+            Err("the delimiter must be a single character".to_string())
+        }
+    })?;
+
+    // unwrap is fine because the argument has a default value
+    let round = match args.value_of(options::ROUND).unwrap() {
+        "up" => RoundMethod::Up,
+        "down" => RoundMethod::Down,
+        "from-zero" => RoundMethod::FromZero,
+        "towards-zero" => RoundMethod::TowardsZero,
+        "nearest" => RoundMethod::Nearest,
+        _ => unreachable!("Should be restricted by clap"),
+    };
+
+    Ok(NumfmtOptions {
+        transform,
+        padding,
+        header,
+        fields,
+        delimiter,
+        round,
+    })
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let result =
+        parse_options(&matches).and_then(|options| match matches.values_of(options::NUMBER) {
+            Some(values) => handle_args(values, options),
+            None => handle_stdin(options),
+        });
+
+    match result {
+        Err(e) => {
+            std::io::stdout().flush().expect("error flushing stdout");
+            show_error!("{}", e);
+            1
+        }
+        _ => 0,
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(LONG_HELP)
+        .setting(AppSettings::AllowNegativeNumbers)
+        .arg(
+            Arg::with_name(options::DELIMITER)
+                .short("d")
+                .long(options::DELIMITER)
+                .value_name("X")
+                .help("use X instead of whitespace for field delimiter"),
+        )
+        .arg(
+            Arg::with_name(options::FIELD)
+                .long(options::FIELD)
+                .help("replace the numbers in these input fields (default=1) see FIELDS below")
+                .value_name("FIELDS")
+                .default_value(options::FIELD_DEFAULT),
+        )
+        .arg(
+            Arg::with_name(options::FROM)
+                .long(options::FROM)
+                .help("auto-scale input numbers to UNITs; see UNIT below")
+                .value_name("UNIT")
+                .default_value(options::FROM_DEFAULT),
+        )
+        .arg(
+            Arg::with_name(options::TO)
+                .long(options::TO)
+                .help("auto-scale output numbers to UNITs; see UNIT below")
+                .value_name("UNIT")
+                .default_value(options::TO_DEFAULT),
+        )
+        .arg(
+            Arg::with_name(options::PADDING)
+                .long(options::PADDING)
+                .help(
+                    "pad the output to N characters; positive N will \
+                     right-align; negative N will left-align; padding is \
+                     ignored if the output is wider than N; the default is \
+                     to automatically pad if a whitespace is found",
+                )
+                .value_name("N"),
+        )
+        .arg(
+            Arg::with_name(options::HEADER)
+                .long(options::HEADER)
+                .help(
+                    "print (without converting) the first N header lines; \
+                     N defaults to 1 if not specified",
+                )
+                .value_name("N")
+                .default_value(options::HEADER_DEFAULT)
+                .hide_default_value(true),
+        )
+        .arg(
+            Arg::with_name(options::ROUND)
+                .long(options::ROUND)
+                .help(
+                    "use METHOD for rounding when scaling; METHOD can be: up,\
+                    down, from-zero (default), towards-zero, nearest",
+                )
+                .value_name("METHOD")
+                .default_value("from-zero")
+                .possible_values(&["up", "down", "from-zero", "towards-zero", "nearest"]),
+        )
+        .arg(Arg::with_name(options::NUMBER).hidden(true).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_numfmt/options.rs.html b/src/uu_numfmt/options.rs.html new file mode 100644 index 000000000..5398eac43 --- /dev/null +++ b/src/uu_numfmt/options.rs.html @@ -0,0 +1,129 @@ +options.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
+use crate::units::Unit;
+use uucore::ranges::Range;
+
+pub const DELIMITER: &str = "delimiter";
+pub const FIELD: &str = "field";
+pub const FIELD_DEFAULT: &str = "1";
+pub const FROM: &str = "from";
+pub const FROM_DEFAULT: &str = "none";
+pub const HEADER: &str = "header";
+pub const HEADER_DEFAULT: &str = "1";
+pub const NUMBER: &str = "NUMBER";
+pub const PADDING: &str = "padding";
+pub const ROUND: &str = "round";
+pub const TO: &str = "to";
+pub const TO_DEFAULT: &str = "none";
+
+pub struct TransformOptions {
+    pub from: Unit,
+    pub to: Unit,
+}
+
+pub struct NumfmtOptions {
+    pub transform: TransformOptions,
+    pub padding: isize,
+    pub header: usize,
+    pub fields: Vec<Range>,
+    pub delimiter: Option<String>,
+    pub round: RoundMethod,
+}
+
+#[derive(Clone, Copy)]
+pub enum RoundMethod {
+    Up,
+    Down,
+    FromZero,
+    TowardsZero,
+    Nearest,
+}
+
+impl RoundMethod {
+    pub fn round(&self, f: f64) -> f64 {
+        match self {
+            RoundMethod::Up => f.ceil(),
+            RoundMethod::Down => f.floor(),
+            RoundMethod::FromZero => {
+                if f < 0.0 {
+                    f.floor()
+                } else {
+                    f.ceil()
+                }
+            }
+            RoundMethod::TowardsZero => {
+                if f < 0.0 {
+                    f.ceil()
+                } else {
+                    f.floor()
+                }
+            }
+            RoundMethod::Nearest => f.round(),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_numfmt/units.rs.html b/src/uu_numfmt/units.rs.html new file mode 100644 index 000000000..6a73dab3c --- /dev/null +++ b/src/uu_numfmt/units.rs.html @@ -0,0 +1,131 @@ +units.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+
+use std::fmt;
+
+pub const SI_BASES: [f64; 10] = [1., 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24, 1e27];
+
+pub const IEC_BASES: [f64; 10] = [
+    1.,
+    1_024.,
+    1_048_576.,
+    1_073_741_824.,
+    1_099_511_627_776.,
+    1_125_899_906_842_624.,
+    1_152_921_504_606_846_976.,
+    1_180_591_620_717_411_303_424.,
+    1_208_925_819_614_629_174_706_176.,
+    1_237_940_039_285_380_274_899_124_224.,
+];
+
+pub type WithI = bool;
+
+pub enum Unit {
+    Auto,
+    Si,
+    Iec(WithI),
+    None,
+}
+
+pub type Result<T> = std::result::Result<T, String>;
+
+#[derive(Clone, Copy, Debug)]
+pub enum RawSuffix {
+    K,
+    M,
+    G,
+    T,
+    P,
+    E,
+    Z,
+    Y,
+}
+
+pub type Suffix = (RawSuffix, WithI);
+
+pub struct DisplayableSuffix(pub Suffix);
+
+impl fmt::Display for DisplayableSuffix {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        let DisplayableSuffix((ref raw_suffix, ref with_i)) = *self;
+        match raw_suffix {
+            RawSuffix::K => write!(f, "K"),
+            RawSuffix::M => write!(f, "M"),
+            RawSuffix::G => write!(f, "G"),
+            RawSuffix::T => write!(f, "T"),
+            RawSuffix::P => write!(f, "P"),
+            RawSuffix::E => write!(f, "E"),
+            RawSuffix::Z => write!(f, "Z"),
+            RawSuffix::Y => write!(f, "Y"),
+        }
+        .and_then(|()| match with_i {
+            true => write!(f, "i"),
+            false => Ok(()),
+        })
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/byteorder_io.rs.html b/src/uu_od/byteorder_io.rs.html new file mode 100644 index 000000000..50ebec5c4 --- /dev/null +++ b/src/uu_od/byteorder_io.rs.html @@ -0,0 +1,109 @@ +byteorder_io.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+
+// spell-checker:ignore (ToDO) byteorder
+
+// workaround until https://github.com/BurntSushi/byteorder/issues/41 has been fixed
+// based on: https://github.com/netvl/immeta/blob/4460ee/src/utils.rs#L76
+
+use byteorder::ByteOrder as ByteOrderTrait;
+use byteorder::{BigEndian, LittleEndian, NativeEndian};
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum ByteOrder {
+    Little,
+    Big,
+    Native,
+}
+
+macro_rules! gen_byte_order_ops {
+    ($($read_name:ident, $write_name:ident -> $tpe:ty),+) => {
+        impl ByteOrder {
+            $(
+            #[allow(dead_code)]
+            #[inline]
+            pub fn $read_name(self, source: &[u8]) -> $tpe {
+                match self {
+                    ByteOrder::Little => LittleEndian::$read_name(source),
+                    ByteOrder::Big => BigEndian::$read_name(source),
+                    ByteOrder::Native => NativeEndian::$read_name(source),
+                }
+            }
+
+            #[allow(dead_code)]
+            pub fn $write_name(self, target: &mut [u8], n: $tpe) {
+                match self {
+                    ByteOrder::Little => LittleEndian::$write_name(target, n),
+                    ByteOrder::Big => BigEndian::$write_name(target, n),
+                    ByteOrder::Native => NativeEndian::$write_name(target, n),
+                }
+            }
+            )+
+        }
+    }
+}
+
+gen_byte_order_ops! {
+    read_u16, write_u16 -> u16,
+    read_u32, write_u32 -> u32,
+    read_u64, write_u64 -> u64,
+    read_i16, write_i16 -> i16,
+    read_i32, write_i32 -> i32,
+    read_i64, write_i64 -> i64,
+    read_f32, write_f32 -> f32,
+    read_f64, write_f64 -> f64
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/formatteriteminfo.rs.html b/src/uu_od/formatteriteminfo.rs.html new file mode 100644 index 000000000..c5ff88010 --- /dev/null +++ b/src/uu_od/formatteriteminfo.rs.html @@ -0,0 +1,123 @@ +formatteriteminfo.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+
+// spell-checker:ignore (ToDO) formatteriteminfo
+
+use std::fmt;
+
+#[allow(clippy::enum_variant_names)]
+#[derive(Copy)]
+pub enum FormatWriter {
+    IntWriter(fn(u64) -> String),
+    FloatWriter(fn(f64) -> String),
+    MultibyteWriter(fn(&[u8]) -> String),
+}
+
+impl Clone for FormatWriter {
+    #[inline]
+    fn clone(&self) -> Self {
+        *self
+    }
+}
+
+impl PartialEq for FormatWriter {
+    fn eq(&self, other: &FormatWriter) -> bool {
+        use crate::formatteriteminfo::FormatWriter::*;
+
+        match (self, other) {
+            (&IntWriter(ref a), &IntWriter(ref b)) => a == b,
+            (&FloatWriter(ref a), &FloatWriter(ref b)) => a == b,
+            (&MultibyteWriter(ref a), &MultibyteWriter(ref b)) => *a as usize == *b as usize,
+            _ => false,
+        }
+    }
+}
+
+impl Eq for FormatWriter {}
+
+impl fmt::Debug for FormatWriter {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            FormatWriter::IntWriter(ref p) => {
+                f.write_str("IntWriter:")?;
+                fmt::Pointer::fmt(p, f)
+            }
+            FormatWriter::FloatWriter(ref p) => {
+                f.write_str("FloatWriter:")?;
+                fmt::Pointer::fmt(p, f)
+            }
+            FormatWriter::MultibyteWriter(ref p) => {
+                f.write_str("MultibyteWriter:")?;
+                fmt::Pointer::fmt(&(*p as *const ()), f)
+            }
+        }
+    }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct FormatterItemInfo {
+    pub byte_size: usize,
+    pub print_width: usize, // including a space in front of the text
+    pub formatter: FormatWriter,
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/inputdecoder.rs.html b/src/uu_od/inputdecoder.rs.html new file mode 100644 index 000000000..1c8e40b69 --- /dev/null +++ b/src/uu_od/inputdecoder.rs.html @@ -0,0 +1,397 @@ +inputdecoder.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+
+use half::f16;
+use std::io;
+
+use crate::byteorder_io::ByteOrder;
+use crate::multifilereader::HasError;
+use crate::peekreader::PeekRead;
+
+/// Processes an input and provides access to the data read in various formats
+///
+/// Currently only useful if the input implements `PeekRead`.
+pub struct InputDecoder<'a, I>
+where
+    I: 'a,
+{
+    /// The input from which data is read
+    input: &'a mut I,
+
+    /// A memory buffer, it's size is set in `new`.
+    data: Vec<u8>,
+    /// The number of bytes in the buffer reserved for the peek data from `PeekRead`.
+    reserved_peek_length: usize,
+
+    /// The number of (valid) bytes in the buffer.
+    used_normal_length: usize,
+    /// The number of peek bytes in the buffer.
+    used_peek_length: usize,
+
+    /// Byte order used to read data from the buffer.
+    byte_order: ByteOrder,
+}
+
+impl<'a, I> InputDecoder<'a, I> {
+    /// Creates a new `InputDecoder` with an allocated buffer of `normal_length` + `peek_length` bytes.
+    /// `byte_order` determines how to read multibyte formats from the buffer.
+    pub fn new(
+        input: &mut I,
+        normal_length: usize,
+        peek_length: usize,
+        byte_order: ByteOrder,
+    ) -> InputDecoder<I> {
+        let bytes = vec![0; normal_length + peek_length];
+
+        InputDecoder {
+            input,
+            data: bytes,
+            reserved_peek_length: peek_length,
+            used_normal_length: 0,
+            used_peek_length: 0,
+            byte_order,
+        }
+    }
+}
+
+impl<'a, I> InputDecoder<'a, I>
+where
+    I: PeekRead,
+{
+    /// calls `peek_read` on the internal stream to (re)fill the buffer. Returns a
+    /// MemoryDecoder providing access to the result or returns an i/o error.
+    pub fn peek_read(&mut self) -> io::Result<MemoryDecoder> {
+        match self
+            .input
+            .peek_read(self.data.as_mut_slice(), self.reserved_peek_length)
+        {
+            Ok((n, p)) => {
+                self.used_normal_length = n;
+                self.used_peek_length = p;
+                Ok(MemoryDecoder {
+                    data: &mut self.data,
+                    used_normal_length: self.used_normal_length,
+                    used_peek_length: self.used_peek_length,
+                    byte_order: self.byte_order,
+                })
+            }
+            Err(e) => Err(e),
+        }
+    }
+}
+
+impl<'a, I> HasError for InputDecoder<'a, I>
+where
+    I: HasError,
+{
+    /// calls has_error on the internal stream.
+    fn has_error(&self) -> bool {
+        self.input.has_error()
+    }
+}
+
+/// Provides access to the internal data in various formats
+pub struct MemoryDecoder<'a> {
+    /// A reference to the parents' data
+    data: &'a mut Vec<u8>,
+    /// The number of (valid) bytes in the buffer.
+    used_normal_length: usize,
+    /// The number of peek bytes in the buffer.
+    used_peek_length: usize,
+    /// Byte order used to read data from the buffer.
+    byte_order: ByteOrder,
+}
+
+impl<'a> MemoryDecoder<'a> {
+    /// Set a part of the internal buffer to zero.
+    /// access to the whole buffer is possible, not just to the valid data.
+    pub fn zero_out_buffer(&mut self, start: usize, end: usize) {
+        for i in start..end {
+            self.data[i] = 0;
+        }
+    }
+
+    /// Returns the current length of the buffer. (ie. how much valid data it contains.)
+    pub fn length(&self) -> usize {
+        self.used_normal_length
+    }
+
+    /// Creates a clone of the internal buffer. The clone only contain the valid data.
+    pub fn clone_buffer(&self, other: &mut Vec<u8>) {
+        other.clone_from(self.data);
+        other.resize(self.used_normal_length, 0);
+    }
+
+    /// Returns a slice to the internal buffer starting at `start`.
+    pub fn get_buffer(&self, start: usize) -> &[u8] {
+        &self.data[start..self.used_normal_length]
+    }
+
+    /// Returns a slice to the internal buffer including the peek data starting at `start`.
+    pub fn get_full_buffer(&self, start: usize) -> &[u8] {
+        &self.data[start..self.used_normal_length + self.used_peek_length]
+    }
+
+    /// Returns a u8/u16/u32/u64 from the internal buffer at position `start`.
+    pub fn read_uint(&self, start: usize, byte_size: usize) -> u64 {
+        match byte_size {
+            1 => u64::from(self.data[start]),
+            2 => u64::from(self.byte_order.read_u16(&self.data[start..start + 2])),
+            4 => u64::from(self.byte_order.read_u32(&self.data[start..start + 4])),
+            8 => self.byte_order.read_u64(&self.data[start..start + 8]),
+            _ => panic!("Invalid byte_size: {}", byte_size),
+        }
+    }
+
+    /// Returns a f32/f64 from the internal buffer at position `start`.
+    pub fn read_float(&self, start: usize, byte_size: usize) -> f64 {
+        match byte_size {
+            2 => f64::from(f16::from_bits(
+                self.byte_order.read_u16(&self.data[start..start + 2]),
+            )),
+            4 => f64::from(self.byte_order.read_f32(&self.data[start..start + 4])),
+            8 => self.byte_order.read_f64(&self.data[start..start + 8]),
+            _ => panic!("Invalid byte_size: {}", byte_size),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::byteorder_io::ByteOrder;
+    use crate::peekreader::PeekReader;
+    use std::io::Cursor;
+
+    #[test]
+    #[allow(clippy::float_cmp)]
+    fn smoke_test() {
+        let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xff, 0xff];
+        let mut input = PeekReader::new(Cursor::new(&data));
+        let mut sut = InputDecoder::new(&mut input, 8, 2, ByteOrder::Little);
+
+        // Peek normal length
+        let mut mem = sut.peek_read().unwrap();
+
+        assert_eq!(8, mem.length());
+
+        assert_eq!(-2.0, mem.read_float(0, 8));
+        assert_eq!(-2.0, mem.read_float(4, 4));
+        assert_eq!(0xc000000000000000, mem.read_uint(0, 8));
+        assert_eq!(0xc0000000, mem.read_uint(4, 4));
+        assert_eq!(0xc000, mem.read_uint(6, 2));
+        assert_eq!(0xc0, mem.read_uint(7, 1));
+        assert_eq!(&[0, 0xc0], mem.get_buffer(6));
+        assert_eq!(&[0, 0xc0, 0xff, 0xff], mem.get_full_buffer(6));
+
+        let mut copy: Vec<u8> = Vec::new();
+        mem.clone_buffer(&mut copy);
+        assert_eq!(vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0], copy);
+
+        mem.zero_out_buffer(7, 8);
+        assert_eq!(&[0, 0, 0xff, 0xff], mem.get_full_buffer(6));
+
+        // Peek tail
+        let mem = sut.peek_read().unwrap();
+        assert_eq!(2, mem.length());
+        assert_eq!(0xffff, mem.read_uint(0, 2));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/inputoffset.rs.html b/src/uu_od/inputoffset.rs.html new file mode 100644 index 000000000..3568d92a0 --- /dev/null +++ b/src/uu_od/inputoffset.rs.html @@ -0,0 +1,233 @@ +inputoffset.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum Radix {
+    Decimal,
+    Hexadecimal,
+    Octal,
+    NoPrefix,
+}
+
+/// provides the byte offset printed at the left margin
+pub struct InputOffset {
+    /// The radix to print the byte offset. NoPrefix will not print a byte offset.
+    radix: Radix,
+    /// The current position. Initialize at `new`, increase using `increase_position`.
+    byte_pos: usize,
+    /// An optional label printed in parentheses, typically different from `byte_pos`,
+    /// but will increase with the same value if `byte_pos` in increased.
+    label: Option<usize>,
+}
+
+impl InputOffset {
+    /// creates a new `InputOffset` using the provided values.
+    pub fn new(radix: Radix, byte_pos: usize, label: Option<usize>) -> InputOffset {
+        InputOffset {
+            radix,
+            byte_pos,
+            label,
+        }
+    }
+
+    /// Increase `byte_pos` and `label` if a label is used.
+    pub fn increase_position(&mut self, n: usize) {
+        self.byte_pos += n;
+        if let Some(l) = self.label {
+            self.label = Some(l + n);
+        }
+    }
+
+    #[cfg(test)]
+    fn set_radix(&mut self, radix: Radix) {
+        self.radix = radix;
+    }
+
+    /// returns a string with the current byte offset
+    pub fn format_byte_offset(&self) -> String {
+        match (self.radix, self.label) {
+            (Radix::Decimal, None) => format!("{:07}", self.byte_pos),
+            (Radix::Decimal, Some(l)) => format!("{:07} ({:07})", self.byte_pos, l),
+            (Radix::Hexadecimal, None) => format!("{:06X}", self.byte_pos),
+            (Radix::Hexadecimal, Some(l)) => format!("{:06X} ({:06X})", self.byte_pos, l),
+            (Radix::Octal, None) => format!("{:07o}", self.byte_pos),
+            (Radix::Octal, Some(l)) => format!("{:07o} ({:07o})", self.byte_pos, l),
+            (Radix::NoPrefix, None) => String::from(""),
+            (Radix::NoPrefix, Some(l)) => format!("({:07o})", l),
+        }
+    }
+
+    /// Prints the byte offset followed by a newline, or nothing at all if
+    /// both `Radix::NoPrefix` was set and no label (--traditional) is used.
+    pub fn print_final_offset(&self) {
+        if self.radix != Radix::NoPrefix || self.label.is_some() {
+            println!("{}", self.format_byte_offset());
+        }
+    }
+}
+
+#[test]
+fn test_input_offset() {
+    let mut sut = InputOffset::new(Radix::Hexadecimal, 10, None);
+    assert_eq!("00000A", &sut.format_byte_offset());
+    sut.increase_position(10);
+    assert_eq!("000014", &sut.format_byte_offset());
+
+    // note normally the radix will not change after initialization
+    sut.set_radix(Radix::Decimal);
+    assert_eq!("0000020", &sut.format_byte_offset());
+
+    sut.set_radix(Radix::Hexadecimal);
+    assert_eq!("000014", &sut.format_byte_offset());
+
+    sut.set_radix(Radix::Octal);
+    assert_eq!("0000024", &sut.format_byte_offset());
+
+    sut.set_radix(Radix::NoPrefix);
+    assert_eq!("", &sut.format_byte_offset());
+
+    sut.increase_position(10);
+    sut.set_radix(Radix::Octal);
+    assert_eq!("0000036", &sut.format_byte_offset());
+}
+
+#[test]
+fn test_input_offset_with_label() {
+    let mut sut = InputOffset::new(Radix::Hexadecimal, 10, Some(20));
+    assert_eq!("00000A (000014)", &sut.format_byte_offset());
+    sut.increase_position(10);
+    assert_eq!("000014 (00001E)", &sut.format_byte_offset());
+
+    // note normally the radix will not change after initialization
+    sut.set_radix(Radix::Decimal);
+    assert_eq!("0000020 (0000030)", &sut.format_byte_offset());
+
+    sut.set_radix(Radix::Hexadecimal);
+    assert_eq!("000014 (00001E)", &sut.format_byte_offset());
+
+    sut.set_radix(Radix::Octal);
+    assert_eq!("0000024 (0000036)", &sut.format_byte_offset());
+
+    sut.set_radix(Radix::NoPrefix);
+    assert_eq!("(0000036)", &sut.format_byte_offset());
+
+    sut.increase_position(10);
+    sut.set_radix(Radix::Octal);
+    assert_eq!("0000036 (0000050)", &sut.format_byte_offset());
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/multifilereader.rs.html b/src/uu_od/multifilereader.rs.html new file mode 100644 index 000000000..05c23d9cc --- /dev/null +++ b/src/uu_od/multifilereader.rs.html @@ -0,0 +1,415 @@ +multifilereader.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+
+// spell-checker:ignore (ToDO) multifile curr fnames fname xfrd fillloop mockstream
+
+use std::fs::File;
+use std::io;
+use std::io::BufReader;
+use std::vec::Vec;
+
+pub enum InputSource<'a> {
+    FileName(&'a str),
+    Stdin,
+    #[allow(dead_code)]
+    Stream(Box<dyn io::Read>),
+}
+
+// MultifileReader - concatenate all our input, file or stdin.
+pub struct MultifileReader<'a> {
+    ni: Vec<InputSource<'a>>,
+    curr_file: Option<Box<dyn io::Read>>,
+    any_err: bool,
+}
+
+pub trait HasError {
+    fn has_error(&self) -> bool;
+}
+
+impl<'b> MultifileReader<'b> {
+    pub fn new(fnames: Vec<InputSource>) -> MultifileReader {
+        let mut mf = MultifileReader {
+            ni: fnames,
+            curr_file: None, // normally this means done; call next_file()
+            any_err: false,
+        };
+        mf.next_file();
+        mf
+    }
+
+    fn next_file(&mut self) {
+        // loop retries with subsequent files if err - normally 'loops' once
+        loop {
+            if self.ni.is_empty() {
+                self.curr_file = None;
+                break;
+            }
+            match self.ni.remove(0) {
+                InputSource::Stdin => {
+                    self.curr_file = Some(Box::new(BufReader::new(std::io::stdin())));
+                    break;
+                }
+                InputSource::FileName(fname) => {
+                    match File::open(fname) {
+                        Ok(f) => {
+                            self.curr_file = Some(Box::new(BufReader::new(f)));
+                            break;
+                        }
+                        Err(e) => {
+                            // If any file can't be opened,
+                            // print an error at the time that the file is needed,
+                            // then move on the the next file.
+                            // This matches the behavior of the original `od`
+                            eprintln!("{}: '{}': {}", uucore::util_name(), fname, e);
+                            self.any_err = true
+                        }
+                    }
+                }
+                InputSource::Stream(s) => {
+                    self.curr_file = Some(s);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+impl<'b> io::Read for MultifileReader<'b> {
+    // Fill buf with bytes read from the list of files
+    // Returns Ok(<number of bytes read>)
+    // Handles io errors itself, thus always returns OK
+    // Fills the provided buffer completely, unless it has run out of input.
+    // If any call returns short (< buf.len()), all subsequent calls will return Ok<0>
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let mut xfrd = 0;
+        // while buffer we are filling is not full.. May go through several files.
+        'fillloop: while xfrd < buf.len() {
+            match self.curr_file {
+                None => break,
+                Some(ref mut curr_file) => {
+                    loop {
+                        // stdin may return on 'return' (enter), even though the buffer isn't full.
+                        xfrd += match curr_file.read(&mut buf[xfrd..]) {
+                            Ok(0) => break,
+                            Ok(n) => n,
+                            Err(e) => {
+                                eprintln!("{}: I/O: {}", uucore::util_name(), e);
+                                self.any_err = true;
+                                break;
+                            }
+                        };
+                        if xfrd == buf.len() {
+                            // transferred all that was asked for.
+                            break 'fillloop;
+                        }
+                    }
+                }
+            }
+            self.next_file();
+        }
+        Ok(xfrd)
+    }
+}
+
+impl<'b> HasError for MultifileReader<'b> {
+    fn has_error(&self) -> bool {
+        self.any_err
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::mockstream::*;
+    use std::io::{Cursor, ErrorKind, Read};
+
+    #[test]
+    fn test_multi_file_reader_one_read() {
+        let inputs = vec![
+            InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))),
+            InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))),
+        ];
+        let mut v = [0; 10];
+
+        let mut sut = MultifileReader::new(inputs);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 8);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41, 0x42, 0x43, 0x44, 0, 0]);
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_multi_file_reader_two_reads() {
+        let inputs = vec![
+            InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))),
+            InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))),
+        ];
+        let mut v = [0; 5];
+
+        let mut sut = MultifileReader::new(inputs);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41]);
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
+        assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
+    }
+
+    #[test]
+    fn test_multi_file_reader_read_error() {
+        let c = Cursor::new(&b"1234"[..])
+            .chain(FailingMockStream::new(ErrorKind::Other, "Failing", 1))
+            .chain(Cursor::new(&b"5678"[..]));
+        let inputs = vec![
+            InputSource::Stream(Box::new(c)),
+            InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))),
+        ];
+        let mut v = [0; 5];
+
+        let mut sut = MultifileReader::new(inputs);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
+        assert_eq!(v, [49, 50, 51, 52, 65]);
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
+        assert_eq!(v, [66, 67, 68, 52, 65]); // last two bytes are not overwritten
+
+        // note: no retry on i/o error, so 5678 is missing
+    }
+
+    #[test]
+    fn test_multi_file_reader_read_error_at_start() {
+        let inputs = vec![
+            InputSource::Stream(Box::new(FailingMockStream::new(
+                ErrorKind::Other,
+                "Failing",
+                1,
+            ))),
+            InputSource::Stream(Box::new(Cursor::new(&b"abcd"[..]))),
+            InputSource::Stream(Box::new(FailingMockStream::new(
+                ErrorKind::Other,
+                "Failing",
+                1,
+            ))),
+            InputSource::Stream(Box::new(Cursor::new(&b"ABCD"[..]))),
+            InputSource::Stream(Box::new(FailingMockStream::new(
+                ErrorKind::Other,
+                "Failing",
+                1,
+            ))),
+        ];
+        let mut v = [0; 5];
+
+        let mut sut = MultifileReader::new(inputs);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 5);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x41]);
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
+        assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/od.rs.html b/src/uu_od/od.rs.html new file mode 100644 index 000000000..27b6d8c66 --- /dev/null +++ b/src/uu_od/od.rs.html @@ -0,0 +1,1287 @@ +od.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Ben Hirsch <benhirsch24@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (clap) DontDelimitTrailingValues
+// spell-checker:ignore (ToDO) formatteriteminfo inputdecoder inputoffset mockstream nrofbytes partialreader odfunc multifile exitcode
+
+#[macro_use]
+extern crate uucore;
+
+mod byteorder_io;
+mod formatteriteminfo;
+mod inputdecoder;
+mod inputoffset;
+#[cfg(test)]
+mod mockstream;
+mod multifilereader;
+mod output_info;
+mod parse_formats;
+mod parse_inputs;
+mod parse_nrofbytes;
+mod partialreader;
+mod peekreader;
+mod prn_char;
+mod prn_float;
+mod prn_int;
+
+use std::cmp;
+
+use crate::byteorder_io::*;
+use crate::formatteriteminfo::*;
+use crate::inputdecoder::{InputDecoder, MemoryDecoder};
+use crate::inputoffset::{InputOffset, Radix};
+use crate::multifilereader::*;
+use crate::output_info::OutputInfo;
+use crate::parse_formats::{parse_format_flags, ParsedFormatterItemInfo};
+use crate::parse_inputs::{parse_inputs, CommandLineInputs};
+use crate::parse_nrofbytes::parse_number_of_bytes;
+use crate::partialreader::*;
+use crate::peekreader::*;
+use crate::prn_char::format_ascii_dump;
+use clap::{self, crate_version, AppSettings, Arg, ArgMatches};
+use uucore::parse_size::ParseSizeError;
+use uucore::InvalidEncodingHandling;
+
+const PEEK_BUFFER_SIZE: usize = 4; // utf-8 can be 4 bytes
+static ABOUT: &str = "dump files in octal and other formats";
+
+static USAGE: &str = r#"
+    od [OPTION]... [--] [FILENAME]...
+    od [-abcdDefFhHiIlLoOsxX] [FILENAME] [[+][0x]OFFSET[.][b]]
+    od --traditional [OPTION]... [FILENAME] [[+][0x]OFFSET[.][b] [[+][0x]LABEL[.][b]]]"#;
+
+static LONG_HELP: &str = r#"
+Displays data in various human-readable formats. If multiple formats are
+specified, the output will contain all formats in the order they appear on the
+command line. Each format will be printed on a new line. Only the line
+containing the first format will be prefixed with the offset.
+
+If no filename is specified, or it is "-", stdin will be used. After a "--", no
+more options will be recognized. This allows for filenames starting with a "-".
+
+If a filename is a valid number which can be used as an offset in the second
+form, you can force it to be recognized as a filename if you include an option
+like "-j0", which is only valid in the first form.
+
+RADIX is one of o,d,x,n for octal, decimal, hexadecimal or none.
+
+BYTES is decimal by default, octal if prefixed with a "0", or hexadecimal if
+prefixed with "0x". The suffixes b, KB, K, MB, M, GB, G, will multiply the
+number with 512, 1000, 1024, 1000^2, 1024^2, 1000^3, 1024^3, 1000^2, 1024^2.
+
+OFFSET and LABEL are octal by default, hexadecimal if prefixed with "0x" or
+decimal if a "." suffix is added. The "b" suffix will multiply with 512.
+
+TYPE contains one or more format specifications consisting of:
+    a       for printable 7-bits ASCII
+    c       for utf-8 characters or octal for undefined characters
+    d[SIZE] for signed decimal
+    f[SIZE] for floating point
+    o[SIZE] for octal
+    u[SIZE] for unsigned decimal
+    x[SIZE] for hexadecimal
+SIZE is the number of bytes which can be the number 1, 2, 4, 8 or 16,
+    or C, I, S, L for 1, 2, 4, 8 bytes for integer types,
+    or F, D, L for 4, 8, 16 bytes for floating point.
+Any type specification can have a "z" suffix, which will add a ASCII dump at
+    the end of the line.
+
+If an error occurred, a diagnostic message will be printed to stderr, and the
+exitcode will be non-zero."#;
+
+pub(crate) mod options {
+    pub const ADDRESS_RADIX: &str = "address-radix";
+    pub const SKIP_BYTES: &str = "skip-bytes";
+    pub const READ_BYTES: &str = "read-bytes";
+    pub const ENDIAN: &str = "endian";
+    pub const STRINGS: &str = "strings";
+    pub const FORMAT: &str = "format";
+    pub const OUTPUT_DUPLICATES: &str = "output-duplicates";
+    pub const TRADITIONAL: &str = "traditional";
+    pub const WIDTH: &str = "width";
+    pub const FILENAME: &str = "FILENAME";
+}
+
+struct OdOptions {
+    byte_order: ByteOrder,
+    skip_bytes: usize,
+    read_bytes: Option<usize>,
+    label: Option<usize>,
+    input_strings: Vec<String>,
+    formats: Vec<ParsedFormatterItemInfo>,
+    line_bytes: usize,
+    output_duplicates: bool,
+    radix: Radix,
+}
+
+impl OdOptions {
+    fn new(matches: ArgMatches, args: Vec<String>) -> Result<OdOptions, String> {
+        let byte_order = match matches.value_of(options::ENDIAN) {
+            None => ByteOrder::Native,
+            Some("little") => ByteOrder::Little,
+            Some("big") => ByteOrder::Big,
+            Some(s) => {
+                return Err(format!("Invalid argument --endian={}", s));
+            }
+        };
+
+        let mut skip_bytes = matches.value_of(options::SKIP_BYTES).map_or(0, |s| {
+            parse_number_of_bytes(s).unwrap_or_else(|e| {
+                crash!(1, "{}", format_error_message(e, s, options::SKIP_BYTES))
+            })
+        });
+
+        let mut label: Option<usize> = None;
+
+        let parsed_input = parse_inputs(&matches).map_err(|e| format!("Invalid inputs: {}", e))?;
+        let input_strings = match parsed_input {
+            CommandLineInputs::FileNames(v) => v,
+            CommandLineInputs::FileAndOffset((f, s, l)) => {
+                skip_bytes = s;
+                label = l;
+                vec![f]
+            }
+        };
+
+        let formats = parse_format_flags(&args)?;
+
+        let mut line_bytes = matches.value_of(options::WIDTH).map_or(16, |s| {
+            if matches.occurrences_of(options::WIDTH) == 0 {
+                return 16;
+            };
+            parse_number_of_bytes(s)
+                .unwrap_or_else(|e| crash!(1, "{}", format_error_message(e, s, options::WIDTH)))
+        });
+
+        let min_bytes = formats.iter().fold(1, |max, next| {
+            cmp::max(max, next.formatter_item_info.byte_size)
+        });
+        if line_bytes == 0 || line_bytes % min_bytes != 0 {
+            show_warning!("invalid width {}; using {} instead", line_bytes, min_bytes);
+            line_bytes = min_bytes;
+        }
+
+        let output_duplicates = matches.is_present(options::OUTPUT_DUPLICATES);
+
+        let read_bytes = matches.value_of(options::READ_BYTES).map(|s| {
+            parse_number_of_bytes(s).unwrap_or_else(|e| {
+                crash!(1, "{}", format_error_message(e, s, options::READ_BYTES))
+            })
+        });
+
+        let radix = match matches.value_of(options::ADDRESS_RADIX) {
+            None => Radix::Octal,
+            Some(s) => {
+                let st = s.as_bytes();
+                if st.len() != 1 {
+                    return Err("Radix must be one of [d, o, n, x]".to_string());
+                } else {
+                    let radix: char =
+                        *(st.get(0).expect("byte string of length 1 lacks a 0th elem")) as char;
+                    match radix {
+                        'd' => Radix::Decimal,
+                        'x' => Radix::Hexadecimal,
+                        'o' => Radix::Octal,
+                        'n' => Radix::NoPrefix,
+                        _ => return Err("Radix must be one of [d, o, n, x]".to_string()),
+                    }
+                }
+            }
+        };
+
+        Ok(OdOptions {
+            byte_order,
+            skip_bytes,
+            read_bytes,
+            label,
+            input_strings,
+            formats,
+            line_bytes,
+            output_duplicates,
+            radix,
+        })
+    }
+}
+
+/// parses and validates command line parameters, prepares data structures,
+/// opens the input and calls `odfunc` to process the input.
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let clap_opts = uu_app();
+
+    let clap_matches = clap_opts
+        .clone() // Clone to reuse clap_opts to print help
+        .get_matches_from(args.clone());
+
+    let od_options = match OdOptions::new(clap_matches, args) {
+        Err(s) => {
+            crash!(1, "{}", s);
+        }
+        Ok(o) => o,
+    };
+
+    let mut input_offset =
+        InputOffset::new(od_options.radix, od_options.skip_bytes, od_options.label);
+
+    let mut input = open_input_peek_reader(
+        &od_options.input_strings,
+        od_options.skip_bytes,
+        od_options.read_bytes,
+    );
+    let mut input_decoder = InputDecoder::new(
+        &mut input,
+        od_options.line_bytes,
+        PEEK_BUFFER_SIZE,
+        od_options.byte_order,
+    );
+
+    let output_info = OutputInfo::new(
+        od_options.line_bytes,
+        &od_options.formats[..],
+        od_options.output_duplicates,
+    );
+
+    odfunc(&mut input_offset, &mut input_decoder, &output_info)
+}
+
+pub fn uu_app() -> clap::App<'static, 'static> {
+    clap::App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .usage(USAGE)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::ADDRESS_RADIX)
+                .short("A")
+                .long(options::ADDRESS_RADIX)
+                .help("Select the base in which file offsets are printed.")
+                .value_name("RADIX"),
+        )
+        .arg(
+            Arg::with_name(options::SKIP_BYTES)
+                .short("j")
+                .long(options::SKIP_BYTES)
+                .help("Skip bytes input bytes before formatting and writing.")
+                .value_name("BYTES"),
+        )
+        .arg(
+            Arg::with_name(options::READ_BYTES)
+                .short("N")
+                .long(options::READ_BYTES)
+                .help("limit dump to BYTES input bytes")
+                .value_name("BYTES"),
+        )
+        .arg(
+            Arg::with_name(options::ENDIAN)
+                .long(options::ENDIAN)
+                .help("byte order to use for multi-byte formats")
+                .possible_values(&["big", "little"])
+                .value_name("big|little"),
+        )
+        .arg(
+            Arg::with_name(options::STRINGS)
+                .short("S")
+                .long(options::STRINGS)
+                .help(
+                    "NotImplemented: output strings of at least BYTES graphic chars. 3 is assumed when \
+                     BYTES is not specified.",
+                )
+                .default_value("3")
+                .value_name("BYTES"),
+        )
+        .arg(
+            Arg::with_name("a")
+                .short("a")
+                .help("named characters, ignoring high-order bit")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("b")
+                .short("b")
+                .help("octal bytes")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("c")
+                .short("c")
+                .help("ASCII characters or backslash escapes")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("d")
+                .short("d")
+                .help("unsigned decimal 2-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("D")
+                .short("D")
+                .help("unsigned decimal 4-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("o")
+                .short("o")
+                .help("octal 2-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("I")
+                .short("I")
+                .help("decimal 8-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("L")
+                .short("L")
+                .help("decimal 8-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("i")
+                .short("i")
+                .help("decimal 4-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("l")
+                .short("l")
+                .help("decimal 8-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("x")
+                .short("x")
+                .help("hexadecimal 2-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("h")
+                .short("h")
+                .help("hexadecimal 2-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("O")
+                .short("O")
+                .help("octal 4-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("s")
+                .short("s")
+                .help("decimal 2-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("X")
+                .short("X")
+                .help("hexadecimal 4-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("H")
+                .short("H")
+                .help("hexadecimal 4-byte units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("e")
+                .short("e")
+                .help("floating point double precision (64-bit) units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("f")
+                .short("f")
+                .help("floating point double precision (32-bit) units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name("F")
+                .short("F")
+                .help("floating point double precision (64-bit) units")
+                .multiple(true)
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::FORMAT)
+                .short("t")
+                .long(options::FORMAT)
+                .help("select output format or formats")
+                .multiple(true)
+                .number_of_values(1)
+                .value_name("TYPE"),
+        )
+        .arg(
+            Arg::with_name(options::OUTPUT_DUPLICATES)
+                .short("v")
+                .long(options::OUTPUT_DUPLICATES)
+                .help("do not use * to mark line suppression")
+                .takes_value(false)
+                .possible_values(&["big", "little"]),
+        )
+        .arg(
+            Arg::with_name(options::WIDTH)
+                .short("w")
+                .long(options::WIDTH)
+                .help(
+                    "output BYTES bytes per output line. 32 is implied when BYTES is not \
+                     specified.",
+                )
+                .default_value("32")
+                .value_name("BYTES"),
+        )
+        .arg(
+            Arg::with_name(options::TRADITIONAL)
+                .long(options::TRADITIONAL)
+                .help("compatibility mode with one input, offset and label.")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::FILENAME)
+                .hidden(true)
+                .multiple(true),
+        )
+        .settings(&[
+            AppSettings::TrailingVarArg,
+            AppSettings::DontDelimitTrailingValues,
+            AppSettings::DisableVersion,
+            AppSettings::DeriveDisplayOrder,
+        ])
+}
+
+/// Loops through the input line by line, calling print_bytes to take care of the output.
+fn odfunc<I>(
+    input_offset: &mut InputOffset,
+    input_decoder: &mut InputDecoder<I>,
+    output_info: &OutputInfo,
+) -> i32
+where
+    I: PeekRead + HasError,
+{
+    let mut duplicate_line = false;
+    let mut previous_bytes: Vec<u8> = Vec::new();
+    let line_bytes = output_info.byte_size_line;
+
+    loop {
+        // print each line data (or multi-format raster of several lines describing the same data).
+
+        match input_decoder.peek_read() {
+            Ok(mut memory_decoder) => {
+                let length = memory_decoder.length();
+
+                if length == 0 {
+                    input_offset.print_final_offset();
+                    break;
+                }
+
+                // not enough byte for a whole element, this should only happen on the last line.
+                if length != line_bytes {
+                    // set zero bytes in the part of the buffer that will be used, but is not filled.
+                    let mut max_used = length + output_info.byte_size_block;
+                    if max_used > line_bytes {
+                        max_used = line_bytes;
+                    }
+
+                    memory_decoder.zero_out_buffer(length, max_used);
+                }
+
+                if !output_info.output_duplicates
+                    && length == line_bytes
+                    && memory_decoder.get_buffer(0) == &previous_bytes[..]
+                {
+                    if !duplicate_line {
+                        duplicate_line = true;
+                        println!("*");
+                    }
+                } else {
+                    duplicate_line = false;
+                    if length == line_bytes {
+                        // save a copy of the input unless it is the last line
+                        memory_decoder.clone_buffer(&mut previous_bytes);
+                    }
+
+                    print_bytes(
+                        &input_offset.format_byte_offset(),
+                        &memory_decoder,
+                        output_info,
+                    );
+                }
+
+                input_offset.increase_position(length);
+            }
+            Err(e) => {
+                show_error!("{}", e);
+                input_offset.print_final_offset();
+                return 1;
+            }
+        };
+    }
+
+    if input_decoder.has_error() {
+        1
+    } else {
+        0
+    }
+}
+
+/// Outputs a single line of input, into one or more lines human readable output.
+fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &OutputInfo) {
+    let mut first = true; // First line of a multi-format raster.
+    for f in output_info.spaced_formatters_iter() {
+        let mut output_text = String::new();
+
+        let mut b = 0;
+        while b < input_decoder.length() {
+            output_text.push_str(&format!(
+                "{:>width$}",
+                "",
+                width = f.spacing[b % output_info.byte_size_block]
+            ));
+
+            match f.formatter_item_info.formatter {
+                FormatWriter::IntWriter(func) => {
+                    let p = input_decoder.read_uint(b, f.formatter_item_info.byte_size);
+                    output_text.push_str(&func(p));
+                }
+                FormatWriter::FloatWriter(func) => {
+                    let p = input_decoder.read_float(b, f.formatter_item_info.byte_size);
+                    output_text.push_str(&func(p));
+                }
+                FormatWriter::MultibyteWriter(func) => {
+                    output_text.push_str(&func(input_decoder.get_full_buffer(b)));
+                }
+            }
+
+            b += f.formatter_item_info.byte_size;
+        }
+
+        if f.add_ascii_dump {
+            let missing_spacing = output_info
+                .print_width_line
+                .saturating_sub(output_text.chars().count());
+            output_text.push_str(&format!(
+                "{:>width$}  {}",
+                "",
+                format_ascii_dump(input_decoder.get_buffer(0)),
+                width = missing_spacing
+            ));
+        }
+
+        if first {
+            print!("{}", prefix); // print offset
+                                  // if printing in multiple formats offset is printed only once
+            first = false;
+        } else {
+            // this takes the space of the file offset on subsequent
+            // lines of multi-format rasters.
+            print!("{:>width$}", "", width = prefix.chars().count());
+        }
+        println!("{}", output_text);
+    }
+}
+
+/// returns a reader implementing `PeekRead + Read + HasError` providing the combined input
+///
+/// `skip_bytes` is the number of bytes skipped from the input
+/// `read_bytes` is an optional limit to the number of bytes to read
+fn open_input_peek_reader(
+    input_strings: &[String],
+    skip_bytes: usize,
+    read_bytes: Option<usize>,
+) -> PeekReader<PartialReader<MultifileReader>> {
+    // should return  "impl PeekRead + Read + HasError" when supported in (stable) rust
+    let inputs = input_strings
+        .iter()
+        .map(|w| match w as &str {
+            "-" => InputSource::Stdin,
+            x => InputSource::FileName(x),
+        })
+        .collect::<Vec<_>>();
+
+    let mf = MultifileReader::new(inputs);
+    let pr = PartialReader::new(mf, skip_bytes, read_bytes);
+    PeekReader::new(pr)
+}
+
+fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String {
+    // NOTE:
+    // GNU's od echos affected flag, -N or --read-bytes (-j or --skip-bytes, etc.), depending user's selection
+    // GNU's od does distinguish between "invalid (suffix in) argument"
+    match error {
+        ParseSizeError::ParseFailure(_) => format!("invalid --{} argument '{}'", option, s),
+        ParseSizeError::SizeTooBig(_) => format!("--{} argument '{}' too large", option, s),
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/output_info.rs.html b/src/uu_od/output_info.rs.html new file mode 100644 index 000000000..9bdcfd912 --- /dev/null +++ b/src/uu_od/output_info.rs.html @@ -0,0 +1,901 @@ +output_info.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+
+// spell-checker:ignore formatteriteminfo blocksize thisblock
+
+use std::cmp;
+use std::slice::Iter;
+
+use crate::formatteriteminfo::FormatterItemInfo;
+use crate::parse_formats::ParsedFormatterItemInfo;
+
+/// Size in bytes of the max datatype. ie set to 16 for 128-bit numbers.
+const MAX_BYTES_PER_UNIT: usize = 8;
+
+/// Contains information to output single output line in human readable form
+pub struct SpacedFormatterItemInfo {
+    /// Contains a function pointer to output data, and information about the output format.
+    pub formatter_item_info: FormatterItemInfo,
+    /// Contains the number of spaces to add to align data with other output formats.
+    ///
+    /// If the corresponding data is a single byte, each entry in this array contains
+    /// the number of spaces to insert when outputting each byte. If the corresponding
+    /// data is multi-byte, only the fist byte position is used. For example a 32-bit
+    /// datatype, could use positions 0, 4, 8, 12, ....
+    /// As each block is formatted identically, only the spacing for a single block is set.
+    pub spacing: [usize; MAX_BYTES_PER_UNIT],
+    /// if set adds a ascii dump at the end of the line
+    pub add_ascii_dump: bool,
+}
+
+/// Contains information about all output lines.
+pub struct OutputInfo {
+    /// The number of bytes of a line.
+    pub byte_size_line: usize,
+    /// The width of a line in human readable format.
+    pub print_width_line: usize,
+
+    /// The number of bytes in a block. (This is the size of the largest datatype in `spaced_formatters`.)
+    pub byte_size_block: usize,
+    /// The width of a block in human readable format. (The size of the largest format.)
+    pub print_width_block: usize,
+    /// All formats.
+    spaced_formatters: Vec<SpacedFormatterItemInfo>,
+    /// determines if duplicate output lines should be printed, or
+    /// skipped with a "*" showing one or more skipped lines.
+    pub output_duplicates: bool,
+}
+
+impl OutputInfo {
+    /// Returns an iterator over the `SpacedFormatterItemInfo` vector.
+    pub fn spaced_formatters_iter(&self) -> Iter<SpacedFormatterItemInfo> {
+        self.spaced_formatters.iter()
+    }
+
+    /// Creates a new `OutputInfo` based on the parameters
+    pub fn new(
+        line_bytes: usize,
+        formats: &[ParsedFormatterItemInfo],
+        output_duplicates: bool,
+    ) -> OutputInfo {
+        let byte_size_block = formats.iter().fold(1, |max, next| {
+            cmp::max(max, next.formatter_item_info.byte_size)
+        });
+        let print_width_block = formats.iter().fold(1, |max, next| {
+            cmp::max(
+                max,
+                next.formatter_item_info.print_width
+                    * (byte_size_block / next.formatter_item_info.byte_size),
+            )
+        });
+        let print_width_line = print_width_block * (line_bytes / byte_size_block);
+
+        let spaced_formatters =
+            OutputInfo::create_spaced_formatter_info(formats, byte_size_block, print_width_block);
+
+        OutputInfo {
+            byte_size_line: line_bytes,
+            print_width_line,
+            byte_size_block,
+            print_width_block,
+            spaced_formatters,
+            output_duplicates,
+        }
+    }
+
+    fn create_spaced_formatter_info(
+        formats: &[ParsedFormatterItemInfo],
+        byte_size_block: usize,
+        print_width_block: usize,
+    ) -> Vec<SpacedFormatterItemInfo> {
+        formats
+            .iter()
+            .map(|f| SpacedFormatterItemInfo {
+                formatter_item_info: f.formatter_item_info,
+                add_ascii_dump: f.add_ascii_dump,
+                spacing: OutputInfo::calculate_alignment(f, byte_size_block, print_width_block),
+            })
+            .collect()
+    }
+
+    /// calculates proper alignment for a single line of output
+    ///
+    /// Multiple representations of the same data, will be right-aligned for easy reading.
+    /// For example a 64 bit octal and a 32-bit decimal with a 16-bit hexadecimal looks like this:
+    /// ```ignore
+    /// 1777777777777777777777 1777777777777777777777
+    ///  4294967295 4294967295  4294967295 4294967295
+    ///   ffff ffff  ffff ffff   ffff ffff  ffff ffff
+    /// ```
+    /// In this example is additional spacing before the first and third decimal number,
+    /// and there is additional spacing before the 1st, 3rd, 5th and 7th hexadecimal number.
+    /// This way both the octal and decimal, as well as the decimal and hexadecimal numbers
+    /// left align. Note that the alignment below both octal numbers is identical.
+    ///
+    /// This function calculates the required spacing for a single line, given the size
+    /// of a block, and the width of a block. The size of a block is the largest type
+    /// and the width is width of the the type which needs the most space to print that
+    /// number of bytes. So both numbers might refer to different types. All widths
+    /// include a space at the front. For example the width of a 8-bit hexadecimal,
+    /// is 3 characters, for example " FF".
+    ///
+    /// This algorithm first calculates how many spaces needs to be added, based the
+    /// block size and the size of the type, and the widths of the block and the type.
+    /// The required spaces are spread across the available positions.
+    /// If the blocksize is 8, and the size of the type is 8 too, there will be just
+    /// one value in a block, so all spacing will be assigned to position 0.
+    /// If the blocksize is 8, and the size of the type is 2, the spacing will be
+    /// spread across position 0, 2, 4, 6. All 4 positions will get an additional
+    /// space as long as there are more then 4 spaces available. If there are 2
+    /// spaces available, they will be assigned to position 0 and 4. If there is
+    /// 1 space available, it will be assigned to position 0. This will be combined,
+    /// For example 7 spaces will be assigned to position 0, 2, 4, 6 like: 3, 1, 2, 1.
+    /// And 7 spaces with 2 positions will be assigned to position 0 and 4 like 4, 3.
+    ///
+    /// Here is another example showing the alignment of 64-bit unsigned decimal numbers,
+    /// 32-bit hexadecimal number, 16-bit octal numbers and 8-bit hexadecimal numbers:
+    /// ```ignore
+    ///        18446744073709551615        18446744073709551615
+    ///      ffffffff      ffffffff      ffffffff      ffffffff
+    /// 177777 177777 177777 177777 177777 177777 177777 177777
+    ///  ff ff  ff ff  ff ff  ff ff  ff ff  ff ff  ff ff  ff ff
+    /// ```
+    ///
+    /// This algorithm assumes the size of all types is a power of 2 (1, 2, 4, 8, 16, ...)
+    /// Increase MAX_BYTES_PER_UNIT to allow larger types.
+    fn calculate_alignment(
+        sf: &dyn TypeSizeInfo,
+        byte_size_block: usize,
+        print_width_block: usize,
+    ) -> [usize; MAX_BYTES_PER_UNIT] {
+        if byte_size_block > MAX_BYTES_PER_UNIT {
+            panic!(
+                "{}-bits types are unsupported. Current max={}-bits.",
+                8 * byte_size_block,
+                8 * MAX_BYTES_PER_UNIT
+            );
+        }
+        let mut spacing = [0; MAX_BYTES_PER_UNIT];
+
+        let mut byte_size = sf.byte_size();
+        let mut items_in_block = byte_size_block / byte_size;
+        let thisblock_width = sf.print_width() * items_in_block;
+        let mut missing_spacing = print_width_block - thisblock_width;
+
+        while items_in_block > 0 {
+            let avg_spacing: usize = missing_spacing / items_in_block;
+            for i in 0..items_in_block {
+                spacing[i * byte_size] += avg_spacing;
+                missing_spacing -= avg_spacing;
+            }
+
+            items_in_block /= 2;
+            byte_size *= 2;
+        }
+
+        spacing
+    }
+}
+
+trait TypeSizeInfo {
+    fn byte_size(&self) -> usize;
+    fn print_width(&self) -> usize;
+}
+
+impl TypeSizeInfo for ParsedFormatterItemInfo {
+    fn byte_size(&self) -> usize {
+        self.formatter_item_info.byte_size
+    }
+    fn print_width(&self) -> usize {
+        self.formatter_item_info.print_width
+    }
+}
+
+#[cfg(test)]
+struct TypeInfo {
+    byte_size: usize,
+    print_width: usize,
+}
+
+#[cfg(test)]
+impl TypeSizeInfo for TypeInfo {
+    fn byte_size(&self) -> usize {
+        self.byte_size
+    }
+    fn print_width(&self) -> usize {
+        self.print_width
+    }
+}
+
+#[test]
+fn test_calculate_alignment() {
+    // For this example `byte_size_block` is 8 and 'print_width_block' is 23:
+    // 1777777777777777777777 1777777777777777777777
+    //  4294967295 4294967295  4294967295 4294967295
+    //   ffff ffff  ffff ffff   ffff ffff  ffff ffff
+
+    // the first line has no additional spacing:
+    assert_eq!(
+        [0, 0, 0, 0, 0, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 8,
+                print_width: 23,
+            },
+            8,
+            23
+        )
+    );
+    // the second line a single space at the start of the block:
+    assert_eq!(
+        [1, 0, 0, 0, 0, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 4,
+                print_width: 11,
+            },
+            8,
+            23
+        )
+    );
+    // the third line two spaces at pos 0, and 1 space at pos 4:
+    assert_eq!(
+        [2, 0, 0, 0, 1, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 2,
+                print_width: 5,
+            },
+            8,
+            23
+        )
+    );
+
+    // For this example `byte_size_block` is 8 and 'print_width_block' is 28:
+    //        18446744073709551615        18446744073709551615
+    //      ffffffff      ffffffff      ffffffff      ffffffff
+    // 177777 177777 177777 177777 177777 177777 177777 177777
+    //  ff ff  ff ff  ff ff  ff ff  ff ff  ff ff  ff ff  ff ff
+
+    assert_eq!(
+        [7, 0, 0, 0, 0, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 8,
+                print_width: 21,
+            },
+            8,
+            28
+        )
+    );
+    assert_eq!(
+        [5, 0, 0, 0, 5, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 4,
+                print_width: 9,
+            },
+            8,
+            28
+        )
+    );
+    assert_eq!(
+        [0, 0, 0, 0, 0, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 2,
+                print_width: 7,
+            },
+            8,
+            28
+        )
+    );
+    assert_eq!(
+        [1, 0, 1, 0, 1, 0, 1, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 3,
+            },
+            8,
+            28
+        )
+    );
+
+    // 9 tests where 8 .. 16 spaces are spread across 8 positions
+    assert_eq!(
+        [1, 1, 1, 1, 1, 1, 1, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 8
+        )
+    );
+    assert_eq!(
+        [2, 1, 1, 1, 1, 1, 1, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 9
+        )
+    );
+    assert_eq!(
+        [2, 1, 1, 1, 2, 1, 1, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 10
+        )
+    );
+    assert_eq!(
+        [3, 1, 1, 1, 2, 1, 1, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 11
+        )
+    );
+    assert_eq!(
+        [2, 1, 2, 1, 2, 1, 2, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 12
+        )
+    );
+    assert_eq!(
+        [3, 1, 2, 1, 2, 1, 2, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 13
+        )
+    );
+    assert_eq!(
+        [3, 1, 2, 1, 3, 1, 2, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 14
+        )
+    );
+    assert_eq!(
+        [4, 1, 2, 1, 3, 1, 2, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 15
+        )
+    );
+    assert_eq!(
+        [2, 2, 2, 2, 2, 2, 2, 2],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 16
+        )
+    );
+
+    // 4 tests where 15 spaces are spread across 8, 4, 2 or 1 position(s)
+    assert_eq!(
+        [4, 1, 2, 1, 3, 1, 2, 1],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 1,
+                print_width: 2,
+            },
+            8,
+            16 + 15
+        )
+    );
+    assert_eq!(
+        [5, 0, 3, 0, 4, 0, 3, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 2,
+                print_width: 4,
+            },
+            8,
+            16 + 15
+        )
+    );
+    assert_eq!(
+        [8, 0, 0, 0, 7, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 4,
+                print_width: 8,
+            },
+            8,
+            16 + 15
+        )
+    );
+    assert_eq!(
+        [15, 0, 0, 0, 0, 0, 0, 0],
+        OutputInfo::calculate_alignment(
+            &TypeInfo {
+                byte_size: 8,
+                print_width: 16,
+            },
+            8,
+            16 + 15
+        )
+    );
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/parse_formats.rs.html b/src/uu_od/parse_formats.rs.html new file mode 100644 index 000000000..e21e83bc6 --- /dev/null +++ b/src/uu_od/parse_formats.rs.html @@ -0,0 +1,1079 @@ +parse_formats.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+
+// spell-checker:ignore formatteriteminfo docopt fvox fvoxw vals acdx
+
+use crate::formatteriteminfo::FormatterItemInfo;
+use crate::prn_char::*;
+use crate::prn_float::*;
+use crate::prn_int::*;
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+pub struct ParsedFormatterItemInfo {
+    pub formatter_item_info: FormatterItemInfo,
+    pub add_ascii_dump: bool,
+}
+
+impl ParsedFormatterItemInfo {
+    pub fn new(
+        formatter_item_info: FormatterItemInfo,
+        add_ascii_dump: bool,
+    ) -> ParsedFormatterItemInfo {
+        ParsedFormatterItemInfo {
+            formatter_item_info,
+            add_ascii_dump,
+        }
+    }
+}
+
+fn od_argument_traditional_format(ch: char) -> Option<FormatterItemInfo> {
+    match ch {
+        'a' => Some(FORMAT_ITEM_A),
+        'B' => Some(FORMAT_ITEM_OCT16),
+        'b' => Some(FORMAT_ITEM_OCT8),
+        'c' => Some(FORMAT_ITEM_C),
+        'D' => Some(FORMAT_ITEM_DEC32U),
+        'd' => Some(FORMAT_ITEM_DEC16U),
+        'e' => Some(FORMAT_ITEM_F64),
+        'F' => Some(FORMAT_ITEM_F64),
+        'f' => Some(FORMAT_ITEM_F32),
+        'H' => Some(FORMAT_ITEM_HEX32),
+        'h' => Some(FORMAT_ITEM_HEX16),
+        'i' => Some(FORMAT_ITEM_DEC32S),
+        'I' => Some(FORMAT_ITEM_DEC64S),
+        'L' => Some(FORMAT_ITEM_DEC64S),
+        'l' => Some(FORMAT_ITEM_DEC64S),
+        'O' => Some(FORMAT_ITEM_OCT32),
+        'o' => Some(FORMAT_ITEM_OCT16),
+        's' => Some(FORMAT_ITEM_DEC16S),
+        'X' => Some(FORMAT_ITEM_HEX32),
+        'x' => Some(FORMAT_ITEM_HEX16),
+        _ => None,
+    }
+}
+
+fn od_format_type(type_char: FormatType, byte_size: u8) -> Option<FormatterItemInfo> {
+    match (type_char, byte_size) {
+        (FormatType::Ascii, _) => Some(FORMAT_ITEM_A),
+        (FormatType::Char, _) => Some(FORMAT_ITEM_C),
+
+        (FormatType::DecimalInt, 1) => Some(FORMAT_ITEM_DEC8S),
+        (FormatType::DecimalInt, 2) => Some(FORMAT_ITEM_DEC16S),
+        (FormatType::DecimalInt, 0) | (FormatType::DecimalInt, 4) => Some(FORMAT_ITEM_DEC32S),
+        (FormatType::DecimalInt, 8) => Some(FORMAT_ITEM_DEC64S),
+
+        (FormatType::OctalInt, 1) => Some(FORMAT_ITEM_OCT8),
+        (FormatType::OctalInt, 2) => Some(FORMAT_ITEM_OCT16),
+        (FormatType::OctalInt, 0) | (FormatType::OctalInt, 4) => Some(FORMAT_ITEM_OCT32),
+        (FormatType::OctalInt, 8) => Some(FORMAT_ITEM_OCT64),
+
+        (FormatType::UnsignedInt, 1) => Some(FORMAT_ITEM_DEC8U),
+        (FormatType::UnsignedInt, 2) => Some(FORMAT_ITEM_DEC16U),
+        (FormatType::UnsignedInt, 0) | (FormatType::UnsignedInt, 4) => Some(FORMAT_ITEM_DEC32U),
+        (FormatType::UnsignedInt, 8) => Some(FORMAT_ITEM_DEC64U),
+
+        (FormatType::HexadecimalInt, 1) => Some(FORMAT_ITEM_HEX8),
+        (FormatType::HexadecimalInt, 2) => Some(FORMAT_ITEM_HEX16),
+        (FormatType::HexadecimalInt, 0) | (FormatType::HexadecimalInt, 4) => {
+            Some(FORMAT_ITEM_HEX32)
+        }
+        (FormatType::HexadecimalInt, 8) => Some(FORMAT_ITEM_HEX64),
+
+        (FormatType::Float, 2) => Some(FORMAT_ITEM_F16),
+        (FormatType::Float, 0) | (FormatType::Float, 4) => Some(FORMAT_ITEM_F32),
+        (FormatType::Float, 8) => Some(FORMAT_ITEM_F64),
+
+        _ => None,
+    }
+}
+
+fn od_argument_with_option(ch: char) -> bool {
+    matches!(ch, 'A' | 'j' | 'N' | 'S' | 'w')
+}
+
+/// Parses format flags from command line
+///
+/// getopts, docopt, clap don't seem suitable to parse the command line
+/// arguments used for formats. In particular arguments can appear
+/// multiple times and the order they appear in, is significant.
+///
+/// arguments like -f, -o, -x can appear separate or combined: -fox
+/// it can also be mixed with non format related flags like -v: -fvox
+/// arguments with parameters like -w16 can only appear at the end: -fvoxw16
+/// parameters of -t/--format specify 1 or more formats.
+/// if -- appears on the command line, parsing should stop.
+pub fn parse_format_flags(args: &[String]) -> Result<Vec<ParsedFormatterItemInfo>, String> {
+    let mut formats = Vec::new();
+
+    // args[0] is the name of the binary
+    let arg_iter = args.iter().skip(1);
+    let mut expect_type_string = false;
+
+    for arg in arg_iter {
+        if expect_type_string {
+            let v = parse_type_string(arg)?;
+            formats.extend(v.into_iter());
+            expect_type_string = false;
+        } else if arg.starts_with("--") {
+            if arg.len() == 2 {
+                break;
+            }
+            if arg.starts_with("--format=") {
+                let params: String = arg.chars().skip_while(|c| *c != '=').skip(1).collect();
+                let v = parse_type_string(&params)?;
+                formats.extend(v.into_iter());
+            }
+            if arg == "--format" {
+                expect_type_string = true;
+            }
+        } else if arg.starts_with('-') {
+            let flags = arg.chars().skip(1);
+            let mut format_spec = String::new();
+            for c in flags {
+                if expect_type_string {
+                    format_spec.push(c);
+                } else if od_argument_with_option(c) {
+                    break;
+                } else if c == 't' {
+                    expect_type_string = true;
+                } else {
+                    // not every option is a format
+                    if let Some(r) = od_argument_traditional_format(c) {
+                        formats.push(ParsedFormatterItemInfo::new(r, false))
+                    }
+                }
+            }
+            if !format_spec.is_empty() {
+                let v = parse_type_string(&format_spec)?;
+                formats.extend(v.into_iter());
+                expect_type_string = false;
+            }
+        }
+    }
+    if expect_type_string {
+        return Err("missing format specification after '--format' / '-t'".to_string());
+    }
+
+    if formats.is_empty() {
+        formats.push(ParsedFormatterItemInfo::new(FORMAT_ITEM_OCT16, false)); // 2 byte octal is the default
+    }
+
+    Ok(formats)
+}
+
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
+enum FormatType {
+    Ascii,
+    Char,
+    DecimalInt,
+    OctalInt,
+    UnsignedInt,
+    HexadecimalInt,
+    Float,
+}
+
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
+enum FormatTypeCategory {
+    Char,
+    Integer,
+    Float,
+}
+
+fn format_type(ch: char) -> Option<FormatType> {
+    match ch {
+        'a' => Some(FormatType::Ascii),
+        'c' => Some(FormatType::Char),
+        'd' => Some(FormatType::DecimalInt),
+        'o' => Some(FormatType::OctalInt),
+        'u' => Some(FormatType::UnsignedInt),
+        'x' => Some(FormatType::HexadecimalInt),
+        'f' => Some(FormatType::Float),
+        _ => None,
+    }
+}
+
+fn format_type_category(t: FormatType) -> FormatTypeCategory {
+    match t {
+        FormatType::Ascii | FormatType::Char => FormatTypeCategory::Char,
+        FormatType::DecimalInt
+        | FormatType::OctalInt
+        | FormatType::UnsignedInt
+        | FormatType::HexadecimalInt => FormatTypeCategory::Integer,
+        FormatType::Float => FormatTypeCategory::Float,
+    }
+}
+
+fn is_format_size_char(
+    ch: Option<char>,
+    format_type: FormatTypeCategory,
+    byte_size: &mut u8,
+) -> bool {
+    match (format_type, ch) {
+        (FormatTypeCategory::Integer, Some('C')) => {
+            *byte_size = 1;
+            true
+        }
+        (FormatTypeCategory::Integer, Some('S')) => {
+            *byte_size = 2;
+            true
+        }
+        (FormatTypeCategory::Integer, Some('I')) => {
+            *byte_size = 4;
+            true
+        }
+        (FormatTypeCategory::Integer, Some('L')) => {
+            *byte_size = 8;
+            true
+        }
+
+        (FormatTypeCategory::Float, Some('F')) => {
+            *byte_size = 4;
+            true
+        }
+        (FormatTypeCategory::Float, Some('D')) => {
+            *byte_size = 8;
+            true
+        }
+        // FormatTypeCategory::Float, 'L' => *byte_size = 16, // TODO support f128
+        _ => false,
+    }
+}
+
+fn is_format_size_decimal(
+    ch: Option<char>,
+    format_type: FormatTypeCategory,
+    decimal_size: &mut String,
+) -> bool {
+    if format_type == FormatTypeCategory::Char {
+        return false;
+    }
+    match ch {
+        Some(d) if d.is_digit(10) => {
+            decimal_size.push(d);
+            true
+        }
+        _ => false,
+    }
+}
+
+fn is_format_dump_char(ch: Option<char>, show_ascii_dump: &mut bool) -> bool {
+    match ch {
+        Some('z') => {
+            *show_ascii_dump = true;
+            true
+        }
+        _ => false,
+    }
+}
+
+fn parse_type_string(params: &str) -> Result<Vec<ParsedFormatterItemInfo>, String> {
+    let mut formats = Vec::new();
+
+    let mut chars = params.chars();
+    let mut ch = chars.next();
+
+    while let Some(type_char) = ch {
+        let type_char = format_type(type_char).ok_or_else(|| {
+            format!(
+                "unexpected char '{}' in format specification '{}'",
+                type_char, params
+            )
+        })?;
+
+        let type_cat = format_type_category(type_char);
+
+        ch = chars.next();
+
+        let mut byte_size = 0u8;
+        let mut show_ascii_dump = false;
+        if is_format_size_char(ch, type_cat, &mut byte_size) {
+            ch = chars.next();
+        } else {
+            let mut decimal_size = String::new();
+            while is_format_size_decimal(ch, type_cat, &mut decimal_size) {
+                ch = chars.next();
+            }
+            if !decimal_size.is_empty() {
+                byte_size = decimal_size.parse().map_err(|_| {
+                    format!(
+                        "invalid number '{}' in format specification '{}'",
+                        decimal_size, params
+                    )
+                })?;
+            }
+        }
+        if is_format_dump_char(ch, &mut show_ascii_dump) {
+            ch = chars.next();
+        }
+
+        let ft = od_format_type(type_char, byte_size).ok_or_else(|| {
+            format!(
+                "invalid size '{}' in format specification '{}'",
+                byte_size, params
+            )
+        })?;
+        formats.push(ParsedFormatterItemInfo::new(ft, show_ascii_dump));
+    }
+
+    Ok(formats)
+}
+
+#[cfg(test)]
+pub fn parse_format_flags_str(args_str: &[&'static str]) -> Result<Vec<FormatterItemInfo>, String> {
+    let args: Vec<String> = args_str.iter().map(|s| s.to_string()).collect();
+    parse_format_flags(&args).map(|v| {
+        // tests using this function assume add_ascii_dump is not set
+        v.into_iter()
+            .inspect(|f| assert!(!f.add_ascii_dump))
+            .map(|f| f.formatter_item_info)
+            .collect()
+    })
+}
+
+#[test]
+fn test_no_options() {
+    assert_eq!(
+        parse_format_flags_str(&["od"]).unwrap(),
+        vec![FORMAT_ITEM_OCT16]
+    );
+}
+
+#[test]
+fn test_one_option() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-F"]).unwrap(),
+        vec![FORMAT_ITEM_F64]
+    );
+}
+
+#[test]
+fn test_two_separate_options() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-F", "-x"]).unwrap(),
+        vec![FORMAT_ITEM_F64, FORMAT_ITEM_HEX16]
+    );
+}
+
+#[test]
+fn test_two_combined_options() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-Fx"]).unwrap(),
+        vec![FORMAT_ITEM_F64, FORMAT_ITEM_HEX16]
+    );
+}
+
+#[test]
+fn test_ignore_non_format_parameters() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-d", "-Ax"]).unwrap(),
+        vec![FORMAT_ITEM_DEC16U]
+    );
+}
+
+#[test]
+fn test_ignore_separate_parameters() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-I", "-A", "x"]).unwrap(),
+        vec![FORMAT_ITEM_DEC64S]
+    );
+}
+
+#[test]
+fn test_ignore_trailing_vals() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-D", "--", "-x"]).unwrap(),
+        vec![FORMAT_ITEM_DEC32U]
+    );
+}
+
+#[test]
+fn test_invalid_long_format() {
+    parse_format_flags_str(&["od", "--format=X"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=xX"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=aC"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=fI"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=xD"]).unwrap_err();
+
+    parse_format_flags_str(&["od", "--format=xC1"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=x1C"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=xz1"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=xzC"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=xzz"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=xCC"]).unwrap_err();
+
+    parse_format_flags_str(&["od", "--format=c1"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=x256"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=d5"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format=f1"]).unwrap_err();
+}
+
+#[test]
+fn test_long_format_a() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=a"]).unwrap(),
+        vec![FORMAT_ITEM_A]
+    );
+}
+
+#[test]
+fn test_long_format_cz() {
+    assert_eq!(
+        parse_format_flags(&["od".to_string(), "--format=cz".to_string()]).unwrap(),
+        vec![ParsedFormatterItemInfo::new(FORMAT_ITEM_C, true)]
+    );
+}
+
+#[test]
+fn test_long_format_d() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=d8"]).unwrap(),
+        vec![FORMAT_ITEM_DEC64S]
+    );
+}
+
+#[test]
+fn test_long_format_d_default() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=d"]).unwrap(),
+        vec![FORMAT_ITEM_DEC32S]
+    );
+}
+
+#[test]
+fn test_long_format_o_default() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=o"]).unwrap(),
+        vec![FORMAT_ITEM_OCT32]
+    );
+}
+
+#[test]
+fn test_long_format_u_default() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=u"]).unwrap(),
+        vec![FORMAT_ITEM_DEC32U]
+    );
+}
+
+#[test]
+fn test_long_format_x_default() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=x"]).unwrap(),
+        vec![FORMAT_ITEM_HEX32]
+    );
+}
+
+#[test]
+fn test_long_format_f_default() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format=f"]).unwrap(),
+        vec![FORMAT_ITEM_F32]
+    );
+}
+
+#[test]
+fn test_long_format_next_arg() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "--format", "f8"]).unwrap(),
+        vec![FORMAT_ITEM_F64]
+    );
+}
+
+#[test]
+fn test_short_format_next_arg() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-t", "x8"]).unwrap(),
+        vec![FORMAT_ITEM_HEX64]
+    );
+}
+
+#[test]
+fn test_short_format_combined_arg() {
+    assert_eq!(
+        parse_format_flags_str(&["od", "-tu8"]).unwrap(),
+        vec![FORMAT_ITEM_DEC64U]
+    );
+}
+
+#[test]
+fn test_format_next_arg_invalid() {
+    parse_format_flags_str(&["od", "--format", "-v"]).unwrap_err();
+    parse_format_flags_str(&["od", "--format"]).unwrap_err();
+    parse_format_flags_str(&["od", "-t", "-v"]).unwrap_err();
+    parse_format_flags_str(&["od", "-t"]).unwrap_err();
+}
+
+#[test]
+fn test_mixed_formats() {
+    assert_eq!(
+        parse_format_flags(&[
+            "od".to_string(),
+            "--skip-bytes=2".to_string(),
+            "-vItu1z".to_string(),
+            "-N".to_string(),
+            "1000".to_string(),
+            "-xt".to_string(),
+            "acdx1".to_string(),
+            "--format=u2c".to_string(),
+            "--format".to_string(),
+            "f".to_string(),
+            "-xAx".to_string(),
+            "--".to_string(),
+            "-h".to_string(),
+            "--format=f8".to_string(),
+        ])
+        .unwrap(),
+        vec![
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_DEC64S, false), // I
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_DEC8U, true),   // tu1z
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_HEX16, false),  // x
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_A, false),      // ta
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_C, false),      // tc
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_DEC32S, false), // td
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_HEX8, false),   // tx1
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_DEC16U, false), // tu2
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_C, false),      // tc
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_F32, false),    // tf
+            ParsedFormatterItemInfo::new(FORMAT_ITEM_HEX16, false),  // x
+        ]
+    );
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/parse_inputs.rs.html b/src/uu_od/parse_inputs.rs.html new file mode 100644 index 000000000..80a1f573e --- /dev/null +++ b/src/uu_od/parse_inputs.rs.html @@ -0,0 +1,785 @@ +parse_inputs.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+
+use super::options;
+use clap::ArgMatches;
+
+/// Abstraction for getopts
+pub trait CommandLineOpts {
+    /// returns all command line parameters which do not belong to an option.
+    fn inputs(&self) -> Vec<&str>;
+    /// tests if any of the specified options is present.
+    fn opts_present(&self, _: &[&str]) -> bool;
+}
+
+/// Implementation for `getopts`
+impl<'a> CommandLineOpts for ArgMatches<'a> {
+    fn inputs(&self) -> Vec<&str> {
+        self.values_of(options::FILENAME)
+            .map(|values| values.collect())
+            .unwrap_or_default()
+    }
+
+    fn opts_present(&self, opts: &[&str]) -> bool {
+        opts.iter().any(|opt| self.is_present(opt))
+    }
+}
+
+/// Contains the Input filename(s) with an optional offset.
+///
+/// `FileNames` is used for one or more file inputs ("-" = stdin)
+/// `FileAndOffset` is used for a single file input, with an offset
+/// and an optional label. Offset and label are specified in bytes.
+/// `FileAndOffset` will be only used if an offset is specified,
+/// but it might be 0.
+#[derive(PartialEq, Debug)]
+pub enum CommandLineInputs {
+    FileNames(Vec<String>),
+    FileAndOffset((String, usize, Option<usize>)),
+}
+
+/// Interprets the command line inputs of od.
+///
+/// Returns either an unspecified number of filenames.
+/// Or it will return a single filename, with an offset and optional label.
+/// Offset and label are specified in bytes.
+/// '-' is used as filename if stdin is meant. This is also returned if
+/// there is no input, as stdin is the default input.
+pub fn parse_inputs(matches: &dyn CommandLineOpts) -> Result<CommandLineInputs, String> {
+    let mut input_strings = matches.inputs();
+
+    if matches.opts_present(&["traditional"]) {
+        return parse_inputs_traditional(input_strings);
+    }
+
+    // test if command line contains: [file] <offset>
+    // fall-through if no (valid) offset is found
+    if input_strings.len() == 1 || input_strings.len() == 2 {
+        // if any of the options -A, -j, -N, -t, -v or -w are present there is no offset
+        if !matches.opts_present(&["A", "j", "N", "t", "v", "w"]) {
+            // test if the last input can be parsed as an offset.
+            let offset = parse_offset_operand(input_strings[input_strings.len() - 1]);
+            if let Ok(n) = offset {
+                // if there is just 1 input (stdin), an offset must start with '+'
+                if input_strings.len() == 1 && input_strings[0].starts_with('+') {
+                    return Ok(CommandLineInputs::FileAndOffset(("-".to_string(), n, None)));
+                }
+                if input_strings.len() == 2 {
+                    return Ok(CommandLineInputs::FileAndOffset((
+                        input_strings[0].to_string(),
+                        n,
+                        None,
+                    )));
+                }
+            }
+        }
+    }
+
+    if input_strings.is_empty() {
+        input_strings.push("-");
+    }
+    Ok(CommandLineInputs::FileNames(
+        input_strings.iter().map(|&s| s.to_string()).collect(),
+    ))
+}
+
+/// interprets inputs when --traditional is on the command line
+///
+/// normally returns CommandLineInputs::FileAndOffset, but if no offset is found,
+/// it returns CommandLineInputs::FileNames (also to differentiate from the offset == 0)
+pub fn parse_inputs_traditional(input_strings: Vec<&str>) -> Result<CommandLineInputs, String> {
+    match input_strings.len() {
+        0 => Ok(CommandLineInputs::FileNames(vec!["-".to_string()])),
+        1 => {
+            let offset0 = parse_offset_operand(input_strings[0]);
+            Ok(match offset0 {
+                Ok(n) => CommandLineInputs::FileAndOffset(("-".to_string(), n, None)),
+                _ => CommandLineInputs::FileNames(
+                    input_strings.iter().map(|&s| s.to_string()).collect(),
+                ),
+            })
+        }
+        2 => {
+            let offset0 = parse_offset_operand(input_strings[0]);
+            let offset1 = parse_offset_operand(input_strings[1]);
+            match (offset0, offset1) {
+                (Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
+                    "-".to_string(),
+                    n,
+                    Some(m),
+                ))),
+                (_, Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
+                    input_strings[0].to_string(),
+                    m,
+                    None,
+                ))),
+                _ => Err(format!("invalid offset: {}", input_strings[1])),
+            }
+        }
+        3 => {
+            let offset = parse_offset_operand(input_strings[1]);
+            let label = parse_offset_operand(input_strings[2]);
+            match (offset, label) {
+                (Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset((
+                    input_strings[0].to_string(),
+                    n,
+                    Some(m),
+                ))),
+                (Err(_), _) => Err(format!("invalid offset: {}", input_strings[1])),
+                (_, Err(_)) => Err(format!("invalid label: {}", input_strings[2])),
+            }
+        }
+        _ => Err(format!(
+            "too many inputs after --traditional: {}",
+            input_strings[3]
+        )),
+    }
+}
+
+/// parses format used by offset and label on the command line
+pub fn parse_offset_operand(s: &str) -> Result<usize, &'static str> {
+    let mut start = 0;
+    let mut len = s.len();
+    let mut radix = 8;
+    let mut multiply = 1;
+
+    if s.starts_with('+') {
+        start += 1;
+    }
+
+    if s[start..len].starts_with("0x") || s[start..len].starts_with("0X") {
+        start += 2;
+        radix = 16;
+    } else {
+        if s[start..len].ends_with('b') {
+            len -= 1;
+            multiply = 512;
+        }
+        if s[start..len].ends_with('.') {
+            len -= 1;
+            radix = 10;
+        }
+    }
+    match usize::from_str_radix(&s[start..len], radix) {
+        Ok(i) => Ok(i * multiply),
+        Err(_) => Err("parse failed"),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    /// A mock for the command line options type
+    ///
+    /// `inputs` are all command line parameters which do not belong to an option.
+    /// `option_names` are the names of the options on the command line.
+    struct MockOptions<'a> {
+        inputs: Vec<String>,
+        option_names: Vec<&'a str>,
+    }
+
+    impl<'a> MockOptions<'a> {
+        fn new(inputs: Vec<&'a str>, option_names: Vec<&'a str>) -> MockOptions<'a> {
+            MockOptions {
+                inputs: inputs.iter().map(|&s| s.to_string()).collect::<Vec<_>>(),
+                option_names,
+            }
+        }
+    }
+
+    impl<'a> CommandLineOpts for MockOptions<'a> {
+        fn inputs(&self) -> Vec<&str> {
+            self.inputs.iter().map(|s| s.as_str()).collect()
+        }
+        fn opts_present(&self, opts: &[&str]) -> bool {
+            for expected in opts.iter() {
+                for actual in self.option_names.iter() {
+                    if *expected == *actual {
+                        return true;
+                    }
+                }
+            }
+            false
+        }
+    }
+
+    #[test]
+    fn test_parse_inputs_normal() {
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["-".to_string()]),
+            parse_inputs(&MockOptions::new(vec![], vec![])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["-".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["-"], vec![])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["file1".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["file1"], vec![])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["file1".to_string(), "file2".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["file1", "file2"], vec![])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec![
+                "-".to_string(),
+                "file1".to_string(),
+                "file2".to_string(),
+            ]),
+            parse_inputs(&MockOptions::new(vec!["-", "file1", "file2"], vec![])).unwrap()
+        );
+    }
+
+    #[test]
+    fn test_parse_inputs_with_offset() {
+        // offset is found without filename, so stdin will be used.
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)),
+            parse_inputs(&MockOptions::new(vec!["+10"], vec![])).unwrap()
+        );
+
+        // offset must start with "+" if no input is specified.
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["10".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["10"], vec![""])).unwrap()
+        );
+
+        // offset is not valid, so it is considered a filename.
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["+10a".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["+10a"], vec![""])).unwrap()
+        );
+
+        // if -j is included in the command line, there cannot be an offset.
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["+10".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["+10"], vec!["j"])).unwrap()
+        );
+
+        // if -v is included in the command line, there cannot be an offset.
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["+10".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["+10"], vec!["o", "v"])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
+            parse_inputs(&MockOptions::new(vec!["file1", "+10"], vec![])).unwrap()
+        );
+
+        // offset does not need to start with "+" if a filename is included.
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
+            parse_inputs(&MockOptions::new(vec!["file1", "10"], vec![])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["file1".to_string(), "+10a".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["file1", "+10a"], vec![""])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["file1".to_string(), "+10".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["file1", "+10"], vec!["j"])).unwrap()
+        );
+
+        // offset must be last on the command line
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["+10".to_string(), "file1".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["+10", "file1"], vec![""])).unwrap()
+        );
+    }
+
+    #[test]
+    fn test_parse_inputs_traditional() {
+        // it should not return FileAndOffset to signal no offset was entered on the command line.
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["-".to_string()]),
+            parse_inputs(&MockOptions::new(vec![], vec!["traditional"])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileNames(vec!["file1".to_string()]),
+            parse_inputs(&MockOptions::new(vec!["file1"], vec!["traditional"])).unwrap()
+        );
+
+        // offset does not need to start with a +
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)),
+            parse_inputs(&MockOptions::new(vec!["10"], vec!["traditional"])).unwrap()
+        );
+
+        // valid offset and valid label
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("-".to_string(), 8, Some(8))),
+            parse_inputs(&MockOptions::new(vec!["10", "10"], vec!["traditional"])).unwrap()
+        );
+
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
+            parse_inputs(&MockOptions::new(vec!["file1", "10"], vec!["traditional"])).unwrap()
+        );
+
+        // only one file is allowed, it must be the first
+        parse_inputs(&MockOptions::new(vec!["10", "file1"], vec!["traditional"])).unwrap_err();
+
+        assert_eq!(
+            CommandLineInputs::FileAndOffset(("file1".to_string(), 8, Some(8))),
+            parse_inputs(&MockOptions::new(
+                vec!["file1", "10", "10"],
+                vec!["traditional"]
+            ))
+            .unwrap()
+        );
+
+        parse_inputs(&MockOptions::new(
+            vec!["10", "file1", "10"],
+            vec!["traditional"],
+        ))
+        .unwrap_err();
+
+        parse_inputs(&MockOptions::new(
+            vec!["10", "10", "file1"],
+            vec!["traditional"],
+        ))
+        .unwrap_err();
+
+        parse_inputs(&MockOptions::new(
+            vec!["10", "10", "10", "10"],
+            vec!["traditional"],
+        ))
+        .unwrap_err();
+    }
+
+    fn parse_offset_operand_str(s: &str) -> Result<usize, &'static str> {
+        parse_offset_operand(&String::from(s))
+    }
+
+    #[test]
+    fn test_parse_offset_operand_invalid() {
+        parse_offset_operand_str("").unwrap_err();
+        parse_offset_operand_str("a").unwrap_err();
+        parse_offset_operand_str("+").unwrap_err();
+        parse_offset_operand_str("+b").unwrap_err();
+        parse_offset_operand_str("0x1.").unwrap_err();
+        parse_offset_operand_str("0x1.b").unwrap_err();
+        parse_offset_operand_str("-").unwrap_err();
+        parse_offset_operand_str("-1").unwrap_err();
+        parse_offset_operand_str("1e10").unwrap_err();
+    }
+
+    #[test]
+    fn test_parse_offset_operand() {
+        assert_eq!(8, parse_offset_operand_str("10").unwrap()); // default octal
+        assert_eq!(0, parse_offset_operand_str("0").unwrap());
+        assert_eq!(8, parse_offset_operand_str("+10").unwrap()); // optional leading '+'
+        assert_eq!(16, parse_offset_operand_str("0x10").unwrap()); // hex
+        assert_eq!(16, parse_offset_operand_str("0X10").unwrap()); // hex
+        assert_eq!(16, parse_offset_operand_str("+0X10").unwrap()); // hex
+        assert_eq!(10, parse_offset_operand_str("10.").unwrap()); // decimal
+        assert_eq!(10, parse_offset_operand_str("+10.").unwrap()); // decimal
+        assert_eq!(4096, parse_offset_operand_str("10b").unwrap()); // b suffix = *512
+        assert_eq!(4096, parse_offset_operand_str("+10b").unwrap()); // b suffix = *512
+        assert_eq!(5120, parse_offset_operand_str("10.b").unwrap()); // b suffix = *512
+        assert_eq!(5120, parse_offset_operand_str("+10.b").unwrap()); // b suffix = *512
+        assert_eq!(267, parse_offset_operand_str("0x10b").unwrap()); // hex
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/parse_nrofbytes.rs.html b/src/uu_od/parse_nrofbytes.rs.html new file mode 100644 index 000000000..03b41c27f --- /dev/null +++ b/src/uu_od/parse_nrofbytes.rs.html @@ -0,0 +1,187 @@ +parse_nrofbytes.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+
+use uucore::parse_size::{parse_size, ParseSizeError};
+
+pub fn parse_number_of_bytes(s: &str) -> Result<usize, ParseSizeError> {
+    let mut start = 0;
+    let mut len = s.len();
+    let mut radix = 16;
+    let mut multiply = 1;
+
+    if s.starts_with("0x") || s.starts_with("0X") {
+        start = 2;
+    } else if s.starts_with('0') {
+        radix = 8;
+    } else {
+        return parse_size(&s[start..]);
+    }
+
+    let mut ends_with = s.chars().rev();
+    match ends_with.next() {
+        Some('b') if radix != 16 => {
+            multiply = 512;
+            len -= 1;
+        }
+        Some('k') | Some('K') => {
+            multiply = 1024;
+            len -= 1;
+        }
+        Some('m') | Some('M') => {
+            multiply = 1024 * 1024;
+            len -= 1;
+        }
+        Some('G') => {
+            multiply = 1024 * 1024 * 1024;
+            len -= 1;
+        }
+        #[cfg(target_pointer_width = "64")]
+        Some('T') => {
+            multiply = 1024 * 1024 * 1024 * 1024;
+            len -= 1;
+        }
+        #[cfg(target_pointer_width = "64")]
+        Some('P') => {
+            multiply = 1024 * 1024 * 1024 * 1024 * 1024;
+            len -= 1;
+        }
+        #[cfg(target_pointer_width = "64")]
+        Some('E') => {
+            multiply = 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
+            len -= 1;
+        }
+        Some('B') if radix != 16 => {
+            len -= 2;
+            multiply = match ends_with.next() {
+                Some('k') | Some('K') => 1000,
+                Some('m') | Some('M') => 1000 * 1000,
+                Some('G') => 1000 * 1000 * 1000,
+                #[cfg(target_pointer_width = "64")]
+                Some('T') => 1000 * 1000 * 1000 * 1000,
+                #[cfg(target_pointer_width = "64")]
+                Some('P') => 1000 * 1000 * 1000 * 1000 * 1000,
+                #[cfg(target_pointer_width = "64")]
+                Some('E') => 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
+                _ => return Err(ParseSizeError::ParseFailure(s.to_string())),
+            }
+        }
+        _ => {}
+    }
+
+    let factor = match usize::from_str_radix(&s[start..len], radix) {
+        Ok(f) => f,
+        Err(e) => return Err(ParseSizeError::ParseFailure(e.to_string())),
+    };
+    factor
+        .checked_mul(multiply)
+        .ok_or_else(|| ParseSizeError::SizeTooBig(s.to_string()))
+}
+
+#[test]
+fn test_parse_number_of_bytes() {
+    // octal input
+    assert_eq!(8, parse_number_of_bytes("010").unwrap());
+    assert_eq!(8 * 512, parse_number_of_bytes("010b").unwrap());
+    assert_eq!(8 * 1024, parse_number_of_bytes("010k").unwrap());
+    assert_eq!(8 * 1_048_576, parse_number_of_bytes("010m").unwrap());
+
+    // hex input
+    assert_eq!(15, parse_number_of_bytes("0xf").unwrap());
+    assert_eq!(15, parse_number_of_bytes("0XF").unwrap());
+    assert_eq!(27, parse_number_of_bytes("0x1b").unwrap());
+    assert_eq!(16 * 1024, parse_number_of_bytes("0x10k").unwrap());
+    assert_eq!(16 * 1_048_576, parse_number_of_bytes("0x10m").unwrap());
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/partialreader.rs.html b/src/uu_od/partialreader.rs.html new file mode 100644 index 000000000..8de4a3347 --- /dev/null +++ b/src/uu_od/partialreader.rs.html @@ -0,0 +1,425 @@ +partialreader.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+
+// spell-checker:ignore mockstream abcdefgh bcdefgh
+
+use std::cmp;
+use std::io;
+use std::io::Read;
+
+use crate::multifilereader::HasError;
+
+/// When a large number of bytes must be skipped, it will be read into a
+/// dynamically allocated buffer. The buffer will be limited to this size.
+const MAX_SKIP_BUFFER: usize = 16 * 1024;
+
+/// Wrapper for `std::io::Read` which can skip bytes at the beginning
+/// of the input, and it can limit the returned bytes to a particular
+/// number of bytes.
+pub struct PartialReader<R> {
+    inner: R,
+    skip: usize,
+    limit: Option<usize>,
+}
+
+impl<R> PartialReader<R> {
+    /// Create a new `PartialReader` wrapping `inner`, which will skip
+    /// `skip` bytes, and limits the output to `limit` bytes. Set `limit`
+    /// to `None` if there should be no limit.
+    pub fn new(inner: R, skip: usize, limit: Option<usize>) -> Self {
+        PartialReader { inner, skip, limit }
+    }
+}
+
+impl<R: Read> Read for PartialReader<R> {
+    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
+        if self.skip > 0 {
+            let mut bytes = [0; MAX_SKIP_BUFFER];
+
+            while self.skip > 0 {
+                let skip_count = cmp::min(self.skip, MAX_SKIP_BUFFER);
+
+                match self.inner.read(&mut bytes[..skip_count])? {
+                    0 => {
+                        // this is an error as we still have more to skip
+                        return Err(io::Error::new(
+                            io::ErrorKind::UnexpectedEof,
+                            "tried to skip past end of input",
+                        ));
+                    }
+                    n => self.skip -= n,
+                }
+            }
+        }
+
+        match self.limit {
+            None => self.inner.read(out),
+            Some(0) => Ok(0),
+            Some(ref mut limit) => {
+                let slice = if *limit > out.len() {
+                    out
+                } else {
+                    &mut out[0..*limit]
+                };
+                match self.inner.read(slice) {
+                    Err(e) => Err(e),
+                    Ok(r) => {
+                        *limit -= r;
+                        Ok(r)
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl<R: HasError> HasError for PartialReader<R> {
+    fn has_error(&self) -> bool {
+        self.inner.has_error()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::mockstream::*;
+    use std::io::{Cursor, ErrorKind, Read};
+
+    #[test]
+    fn test_read_without_limits() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 0, None);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 8);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0, 0]);
+    }
+
+    #[test]
+    fn test_read_without_limits_with_error() {
+        let mut v = [0; 10];
+        let f = FailingMockStream::new(ErrorKind::PermissionDenied, "No access", 3);
+        let mut sut = PartialReader::new(f, 0, None);
+
+        let error = sut.read(v.as_mut()).unwrap_err();
+        assert_eq!(error.kind(), ErrorKind::PermissionDenied);
+        assert_eq!(error.to_string(), "No access");
+    }
+
+    #[test]
+    fn test_read_skipping_bytes() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 2, None);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 6);
+        assert_eq!(v, [0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0, 0, 0, 0]);
+    }
+
+    #[test]
+    fn test_read_skipping_all() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 20, None);
+
+        let error = sut.read(v.as_mut()).unwrap_err();
+        assert_eq!(error.kind(), ErrorKind::UnexpectedEof);
+    }
+
+    #[test]
+    fn test_read_skipping_with_error() {
+        let mut v = [0; 10];
+        let f = FailingMockStream::new(ErrorKind::PermissionDenied, "No access", 3);
+        let mut sut = PartialReader::new(f, 2, None);
+
+        let error = sut.read(v.as_mut()).unwrap_err();
+        assert_eq!(error.kind(), ErrorKind::PermissionDenied);
+        assert_eq!(error.to_string(), "No access");
+    }
+
+    #[test]
+    fn test_read_skipping_with_two_reads_during_skip() {
+        let mut v = [0; 10];
+        let c = Cursor::new(&b"a"[..]).chain(Cursor::new(&b"bcdefgh"[..]));
+        let mut sut = PartialReader::new(c, 2, None);
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 6);
+        assert_eq!(v, [0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0, 0, 0, 0]);
+    }
+
+    #[test]
+    fn test_read_skipping_huge_number() {
+        let mut v = [0; 10];
+        // test if it does not eat all memory....
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), usize::max_value(), None);
+
+        sut.read(v.as_mut()).unwrap_err();
+    }
+
+    #[test]
+    fn test_read_limiting_all() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 0, Some(0));
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_read_limiting() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 0, Some(6));
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 6);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0, 0, 0, 0]);
+    }
+
+    #[test]
+    fn test_read_limiting_with_error() {
+        let mut v = [0; 10];
+        let f = FailingMockStream::new(ErrorKind::PermissionDenied, "No access", 3);
+        let mut sut = PartialReader::new(f, 0, Some(6));
+
+        let error = sut.read(v.as_mut()).unwrap_err();
+        assert_eq!(error.kind(), ErrorKind::PermissionDenied);
+        assert_eq!(error.to_string(), "No access");
+    }
+
+    #[test]
+    fn test_read_limiting_with_large_limit() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 0, Some(20));
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 8);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0, 0]);
+    }
+
+    #[test]
+    fn test_read_limiting_with_multiple_reads() {
+        let mut v = [0; 3];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 0, Some(6));
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
+        assert_eq!(v, [0x61, 0x62, 0x63]);
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
+        assert_eq!(v, [0x64, 0x65, 0x66]);
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 0);
+    }
+
+    #[test]
+    fn test_read_skipping_and_limiting() {
+        let mut v = [0; 10];
+        let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), 2, Some(4));
+
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 4);
+        assert_eq!(v, [0x63, 0x64, 0x65, 0x66, 0, 0, 0, 0, 0, 0]);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/peekreader.rs.html b/src/uu_od/peekreader.rs.html new file mode 100644 index 000000000..5f2b85d04 --- /dev/null +++ b/src/uu_od/peekreader.rs.html @@ -0,0 +1,435 @@ +peekreader.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+
+// spell-checker:ignore (ToDO) tempbuffer abcdefgh abcdefghij
+
+//! Contains the trait `PeekRead` and type `PeekReader` implementing it.
+
+use std::io;
+use std::io::{Read, Write};
+
+use crate::multifilereader::HasError;
+
+/// A trait which supplies a function to peek into a stream without
+/// actually reading it.
+///
+/// Like `std::io::Read`, it allows to read data from a stream, with
+/// the additional possibility to reserve a part of the returned data
+/// with the data which will be read in subsequent calls.
+///
+pub trait PeekRead {
+    /// Reads data into a buffer.
+    ///
+    /// Fills `out` with data. The last `peek_size` bytes of `out` are
+    /// used for data which keeps available on subsequent calls.
+    /// `peek_size` must be smaller or equal to the size of `out`.
+    ///
+    /// Returns a tuple where the first number is the number of bytes
+    /// read from the stream, and the second number is the number of
+    /// bytes additionally read. Any of the numbers might be zero.
+    /// It can also return an error.
+    ///
+    /// A type implementing this trait, will typically also implement
+    /// `std::io::Read`.
+    ///
+    /// # Panics
+    /// Might panic if `peek_size` is larger then the size of `out`
+    fn peek_read(&mut self, out: &mut [u8], peek_size: usize) -> io::Result<(usize, usize)>;
+}
+
+/// Wrapper for `std::io::Read` allowing to peek into the data to be read.
+pub struct PeekReader<R> {
+    inner: R,
+    temp_buffer: Vec<u8>,
+}
+
+impl<R> PeekReader<R> {
+    /// Create a new `PeekReader` wrapping `inner`
+    pub fn new(inner: R) -> Self {
+        PeekReader {
+            inner,
+            temp_buffer: Vec::new(),
+        }
+    }
+}
+
+impl<R: Read> PeekReader<R> {
+    fn read_from_tempbuffer(&mut self, mut out: &mut [u8]) -> usize {
+        match out.write(self.temp_buffer.as_mut_slice()) {
+            Ok(n) => {
+                self.temp_buffer.drain(..n);
+                n
+            }
+            Err(_) => 0,
+        }
+    }
+
+    fn write_to_tempbuffer(&mut self, bytes: &[u8]) {
+        // if temp_buffer is not empty, data has to be inserted in front
+        let org_buffer: Vec<_> = self.temp_buffer.drain(..).collect();
+        self.temp_buffer.write_all(bytes).unwrap();
+        self.temp_buffer.extend(org_buffer);
+    }
+}
+
+impl<R: Read> Read for PeekReader<R> {
+    fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
+        let start_pos = self.read_from_tempbuffer(out);
+        match self.inner.read(&mut out[start_pos..]) {
+            Err(e) => Err(e),
+            Ok(n) => Ok(n + start_pos),
+        }
+    }
+}
+
+impl<R: Read> PeekRead for PeekReader<R> {
+    /// Reads data into a buffer.
+    ///
+    /// See `PeekRead::peek_read`.
+    ///
+    /// # Panics
+    /// If `peek_size` is larger then the size of `out`
+    fn peek_read(&mut self, out: &mut [u8], peek_size: usize) -> io::Result<(usize, usize)> {
+        assert!(out.len() >= peek_size);
+        match self.read(out) {
+            Err(e) => Err(e),
+            Ok(bytes_in_buffer) => {
+                let unused = out.len() - bytes_in_buffer;
+                if peek_size <= unused {
+                    Ok((bytes_in_buffer, 0))
+                } else {
+                    let actual_peek_size = peek_size - unused;
+                    let real_size = bytes_in_buffer - actual_peek_size;
+                    self.write_to_tempbuffer(&out[real_size..bytes_in_buffer]);
+                    Ok((real_size, actual_peek_size))
+                }
+            }
+        }
+    }
+}
+
+impl<R: HasError> HasError for PeekReader<R> {
+    fn has_error(&self) -> bool {
+        self.inner.has_error()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::io::{Cursor, Read};
+
+    #[test]
+    fn test_read_normal() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefgh"[..]));
+
+        let mut v = [0; 10];
+        assert_eq!(sut.read(v.as_mut()).unwrap(), 8);
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0, 0]);
+    }
+
+    #[test]
+    fn test_peek_read_without_buffer() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefgh"[..]));
+
+        let mut v = [0; 10];
+        assert_eq!(sut.peek_read(v.as_mut(), 0).unwrap(), (8, 0));
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0, 0]);
+    }
+
+    #[test]
+    fn test_peek_read_and_read() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..]));
+
+        let mut v = [0; 8];
+        assert_eq!(sut.peek_read(v.as_mut(), 4).unwrap(), (4, 4));
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]);
+
+        let mut v2 = [0; 8];
+        assert_eq!(sut.read(v2.as_mut()).unwrap(), 6);
+        assert_eq!(v2, [0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0, 0]);
+    }
+
+    #[test]
+    fn test_peek_read_multiple_times() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..]));
+
+        let mut s1 = [0; 8];
+        assert_eq!(sut.peek_read(s1.as_mut(), 4).unwrap(), (4, 4));
+        assert_eq!(s1, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]);
+
+        let mut s2 = [0; 8];
+        assert_eq!(sut.peek_read(s2.as_mut(), 4).unwrap(), (4, 2));
+        assert_eq!(s2, [0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0, 0]);
+
+        let mut s3 = [0; 8];
+        assert_eq!(sut.peek_read(s3.as_mut(), 4).unwrap(), (2, 0));
+        assert_eq!(s3, [0x69, 0x6a, 0, 0, 0, 0, 0, 0]);
+    }
+
+    #[test]
+    fn test_peek_read_and_read_with_small_buffer() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..]));
+
+        let mut v = [0; 8];
+        assert_eq!(sut.peek_read(v.as_mut(), 4).unwrap(), (4, 4));
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]);
+
+        let mut v2 = [0; 2];
+        assert_eq!(sut.read(v2.as_mut()).unwrap(), 2);
+        assert_eq!(v2, [0x65, 0x66]);
+        assert_eq!(sut.read(v2.as_mut()).unwrap(), 2);
+        assert_eq!(v2, [0x67, 0x68]);
+        assert_eq!(sut.read(v2.as_mut()).unwrap(), 2);
+        assert_eq!(v2, [0x69, 0x6a]);
+    }
+
+    #[test]
+    fn test_peek_read_with_smaller_buffer() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..]));
+
+        let mut v = [0; 8];
+        assert_eq!(sut.peek_read(v.as_mut(), 4).unwrap(), (4, 4));
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]);
+
+        let mut v2 = [0; 2];
+        assert_eq!(sut.peek_read(v2.as_mut(), 2).unwrap(), (0, 2));
+        assert_eq!(v2, [0x65, 0x66]);
+        assert_eq!(sut.peek_read(v2.as_mut(), 0).unwrap(), (2, 0));
+        assert_eq!(v2, [0x65, 0x66]);
+        assert_eq!(sut.peek_read(v2.as_mut(), 0).unwrap(), (2, 0));
+        assert_eq!(v2, [0x67, 0x68]);
+        assert_eq!(sut.peek_read(v2.as_mut(), 0).unwrap(), (2, 0));
+        assert_eq!(v2, [0x69, 0x6a]);
+    }
+
+    #[test]
+    fn test_peek_read_peek_with_larger_peek_buffer() {
+        let mut sut = PeekReader::new(Cursor::new(&b"abcdefghij"[..]));
+
+        let mut v = [0; 8];
+        assert_eq!(sut.peek_read(v.as_mut(), 4).unwrap(), (4, 4));
+        assert_eq!(v, [0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68]);
+
+        let mut v2 = [0; 8];
+        assert_eq!(sut.peek_read(v2.as_mut(), 8).unwrap(), (0, 6));
+        assert_eq!(v2, [0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0, 0]);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/prn_char.rs.html b/src/uu_od/prn_char.rs.html new file mode 100644 index 000000000..6f476e6d0 --- /dev/null +++ b/src/uu_od/prn_char.rs.html @@ -0,0 +1,315 @@ +prn_char.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+
+use std::str::from_utf8;
+
+use crate::formatteriteminfo::*;
+
+pub static FORMAT_ITEM_A: FormatterItemInfo = FormatterItemInfo {
+    byte_size: 1,
+    print_width: 4,
+    formatter: FormatWriter::IntWriter(format_item_a),
+};
+
+pub static FORMAT_ITEM_C: FormatterItemInfo = FormatterItemInfo {
+    byte_size: 1,
+    print_width: 4,
+    formatter: FormatWriter::MultibyteWriter(format_item_c),
+};
+
+static A_CHARS: [&str; 128] = [
+    "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", "bs", "ht", "nl", "vt", "ff", "cr",
+    "so", "si", "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", "can", "em", "sub", "esc",
+    "fs", "gs", "rs", "us", "sp", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-",
+    ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@",
+    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S",
+    "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f",
+    "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y",
+    "z", "{", "|", "}", "~", "del",
+];
+
+fn format_item_a(p: u64) -> String {
+    // item-bytes == 1
+    let b = (p & 0x7f) as u8;
+    format!("{:>4}", A_CHARS.get(b as usize).unwrap_or(&"??"))
+}
+
+static C_CHARS: [&str; 128] = [
+    "\\0", "001", "002", "003", "004", "005", "006", "\\a", "\\b", "\\t", "\\n", "\\v", "\\f",
+    "\\r", "016", "017", "020", "021", "022", "023", "024", "025", "026", "027", "030", "031",
+    "032", "033", "034", "035", "036", "037", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")",
+    "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<",
+    "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O",
+    "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b",
+    "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
+    "v", "w", "x", "y", "z", "{", "|", "}", "~", "177",
+];
+
+fn format_item_c(bytes: &[u8]) -> String {
+    // item-bytes == 1
+    let b = bytes[0];
+
+    if b & 0x80 == 0x00 {
+        match C_CHARS.get(b as usize) {
+            Some(s) => format!("{:>4}", s),
+            None => format!("{:>4}", b),
+        }
+    } else if (b & 0xc0) == 0x80 {
+        // second or subsequent octet of an utf-8 sequence
+        String::from("  **")
+    } else if ((b & 0xe0) == 0xc0) && (bytes.len() >= 2) {
+        // start of a 2 octet utf-8 sequence
+        match from_utf8(&bytes[0..2]) {
+            Ok(s) => format!("{:>4}", s),
+            Err(_) => format!(" {:03o}", b),
+        }
+    } else if ((b & 0xf0) == 0xe0) && (bytes.len() >= 3) {
+        // start of a 3 octet utf-8 sequence
+        match from_utf8(&bytes[0..3]) {
+            Ok(s) => format!("{:>4}", s),
+            Err(_) => format!(" {:03o}", b),
+        }
+    } else if ((b & 0xf8) == 0xf0) && (bytes.len() >= 4) {
+        // start of a 4 octet utf-8 sequence
+        match from_utf8(&bytes[0..4]) {
+            Ok(s) => format!("{:>4}", s),
+            Err(_) => format!(" {:03o}", b),
+        }
+    } else {
+        // invalid utf-8
+        format!(" {:03o}", b)
+    }
+}
+
+pub fn format_ascii_dump(bytes: &[u8]) -> String {
+    let mut result = String::new();
+
+    result.push('>');
+    for c in bytes.iter() {
+        if *c >= 0x20 && *c <= 0x7e {
+            result.push_str(C_CHARS[*c as usize]);
+        } else {
+            result.push('.');
+        }
+    }
+    result.push('<');
+
+    result
+}
+
+#[test]
+fn test_format_item_a() {
+    assert_eq!(" nul", format_item_a(0x00));
+    assert_eq!(" soh", format_item_a(0x01));
+    assert_eq!("  sp", format_item_a(0x20));
+    assert_eq!("   A", format_item_a(0x41));
+    assert_eq!("   ~", format_item_a(0x7e));
+    assert_eq!(" del", format_item_a(0x7f));
+
+    assert_eq!(" nul", format_item_a(0x80));
+    assert_eq!("   A", format_item_a(0xc1));
+    assert_eq!("   ~", format_item_a(0xfe));
+    assert_eq!(" del", format_item_a(0xff));
+}
+
+#[test]
+fn test_format_item_c() {
+    assert_eq!("  \\0", format_item_c(&[0x00]));
+    assert_eq!(" 001", format_item_c(&[0x01]));
+    assert_eq!("    ", format_item_c(&[0x20]));
+    assert_eq!("   A", format_item_c(&[0x41]));
+    assert_eq!("   ~", format_item_c(&[0x7e]));
+    assert_eq!(" 177", format_item_c(&[0x7f]));
+    assert_eq!("   A", format_item_c(&[0x41, 0x21]));
+
+    assert_eq!("  **", format_item_c(&[0x80]));
+    assert_eq!("  **", format_item_c(&[0x9f]));
+
+    assert_eq!("   ß", format_item_c(&[0xc3, 0x9f]));
+    assert_eq!("   ß", format_item_c(&[0xc3, 0x9f, 0x21]));
+
+    assert_eq!("   \u{1000}", format_item_c(&[0xe1, 0x80, 0x80]));
+    assert_eq!("   \u{1000}", format_item_c(&[0xe1, 0x80, 0x80, 0x21]));
+
+    assert_eq!("   \u{1f496}", format_item_c(&[0xf0, 0x9f, 0x92, 0x96]));
+    assert_eq!(
+        "   \u{1f496}",
+        format_item_c(&[0xf0, 0x9f, 0x92, 0x96, 0x21])
+    );
+
+    assert_eq!(" 300", format_item_c(&[0xc0, 0x80])); // invalid utf-8 (UTF-8 null)
+    assert_eq!(" 301", format_item_c(&[0xc1, 0xa1])); // invalid utf-8
+    assert_eq!(" 303", format_item_c(&[0xc3, 0xc3])); // invalid utf-8
+    assert_eq!(" 360", format_item_c(&[0xf0, 0x82, 0x82, 0xac])); // invalid utf-8 (overlong)
+    assert_eq!(" 360", format_item_c(&[0xf0, 0x9f, 0x92])); // invalid utf-8 (missing octet)
+    assert_eq!("   \u{10FFFD}", format_item_c(&[0xf4, 0x8f, 0xbf, 0xbd])); // largest valid utf-8   // spell-checker:ignore 10FFFD FFFD
+    assert_eq!(" 364", format_item_c(&[0xf4, 0x90, 0x00, 0x00])); // invalid utf-8
+    assert_eq!(" 365", format_item_c(&[0xf5, 0x80, 0x80, 0x80])); // invalid utf-8
+    assert_eq!(" 377", format_item_c(&[0xff])); // invalid utf-8
+}
+
+#[test]
+fn test_format_ascii_dump() {
+    assert_eq!(">.<", format_ascii_dump(&[0x00]));
+    assert_eq!(
+        ">. A~.<",
+        format_ascii_dump(&[0x1f, 0x20, 0x41, 0x7e, 0x7f])
+    );
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/prn_float.rs.html b/src/uu_od/prn_float.rs.html new file mode 100644 index 000000000..ce0148408 --- /dev/null +++ b/src/uu_od/prn_float.rs.html @@ -0,0 +1,449 @@ +prn_float.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+
+use half::f16;
+use std::f32;
+use std::f64;
+use std::num::FpCategory;
+
+use crate::formatteriteminfo::*;
+
+pub static FORMAT_ITEM_F16: FormatterItemInfo = FormatterItemInfo {
+    byte_size: 2,
+    print_width: 10,
+    formatter: FormatWriter::FloatWriter(format_item_flo16),
+};
+
+pub static FORMAT_ITEM_F32: FormatterItemInfo = FormatterItemInfo {
+    byte_size: 4,
+    print_width: 15,
+    formatter: FormatWriter::FloatWriter(format_item_flo32),
+};
+
+pub static FORMAT_ITEM_F64: FormatterItemInfo = FormatterItemInfo {
+    byte_size: 8,
+    print_width: 25,
+    formatter: FormatWriter::FloatWriter(format_item_flo64),
+};
+
+pub fn format_item_flo16(f: f64) -> String {
+    format!(" {}", format_flo16(f16::from_f64(f)))
+}
+
+pub fn format_item_flo32(f: f64) -> String {
+    format!(" {}", format_flo32(f as f32))
+}
+
+pub fn format_item_flo64(f: f64) -> String {
+    format!(" {}", format_flo64(f))
+}
+
+fn format_flo16(f: f16) -> String {
+    format_float(f64::from(f), 9, 4)
+}
+
+// formats float with 8 significant digits, eg 12345678 or -1.2345678e+12
+// always returns a string of 14 characters
+fn format_flo32(f: f32) -> String {
+    let width: usize = 14;
+    let precision: usize = 8;
+
+    if f.classify() == FpCategory::Subnormal {
+        // subnormal numbers will be normal as f64, so will print with a wrong precision
+        format!("{:width$e}", f, width = width) // subnormal numbers
+    } else {
+        format_float(f64::from(f), width, precision)
+    }
+}
+
+fn format_flo64(f: f64) -> String {
+    format_float(f, 24, 17)
+}
+
+fn format_float(f: f64, width: usize, precision: usize) -> String {
+    if !f.is_normal() {
+        if f == -0.0 && f.is_sign_negative() {
+            return format!("{:>width$}", "-0", width = width);
+        }
+        if f == 0.0 || !f.is_finite() {
+            return format!("{:width$}", f, width = width);
+        }
+        return format!("{:width$e}", f, width = width); // subnormal numbers
+    }
+
+    let mut l = f.abs().log10().floor() as i32;
+
+    let r = 10f64.powi(l);
+    if (f > 0.0 && r > f) || (f < 0.0 && -r < f) {
+        // fix precision error
+        l -= 1;
+    }
+
+    if l >= 0 && l <= (precision as i32 - 1) {
+        format!(
+            "{:width$.dec$}",
+            f,
+            width = width,
+            dec = (precision - 1) - l as usize
+        )
+    } else if l == -1 {
+        format!("{:width$.dec$}", f, width = width, dec = precision)
+    } else {
+        format!("{:width$.dec$e}", f, width = width, dec = precision - 1)
+    }
+}
+
+#[test]
+#[allow(clippy::excessive_precision)]
+fn test_format_flo32() {
+    assert_eq!(format_flo32(1.0), "     1.0000000");
+    assert_eq!(format_flo32(9.9999990), "     9.9999990");
+    assert_eq!(format_flo32(10.0), "     10.000000");
+    assert_eq!(format_flo32(99.999977), "     99.999977");
+    assert_eq!(format_flo32(99.999992), "     99.999992");
+    assert_eq!(format_flo32(100.0), "     100.00000");
+    assert_eq!(format_flo32(999.99994), "     999.99994");
+    assert_eq!(format_flo32(1000.0), "     1000.0000");
+    assert_eq!(format_flo32(9999.9990), "     9999.9990");
+    assert_eq!(format_flo32(10000.0), "     10000.000");
+    assert_eq!(format_flo32(99999.992), "     99999.992");
+    assert_eq!(format_flo32(100000.0), "     100000.00");
+    assert_eq!(format_flo32(999999.94), "     999999.94");
+    assert_eq!(format_flo32(1000000.0), "     1000000.0");
+    assert_eq!(format_flo32(9999999.0), "     9999999.0");
+    assert_eq!(format_flo32(10000000.0), "      10000000");
+    assert_eq!(format_flo32(99999992.0), "      99999992");
+    assert_eq!(format_flo32(100000000.0), "   1.0000000e8");
+    assert_eq!(format_flo32(9.9999994e8), "   9.9999994e8");
+    assert_eq!(format_flo32(1.0e9), "   1.0000000e9");
+    assert_eq!(format_flo32(9.9999990e9), "   9.9999990e9");
+    assert_eq!(format_flo32(1.0e10), "  1.0000000e10");
+
+    assert_eq!(format_flo32(0.1), "    0.10000000");
+    assert_eq!(format_flo32(0.99999994), "    0.99999994");
+    assert_eq!(format_flo32(0.010000001), "  1.0000001e-2");
+    assert_eq!(format_flo32(0.099999994), "  9.9999994e-2");
+    assert_eq!(format_flo32(0.001), "  1.0000000e-3");
+    assert_eq!(format_flo32(0.0099999998), "  9.9999998e-3");
+
+    assert_eq!(format_flo32(-1.0), "    -1.0000000");
+    assert_eq!(format_flo32(-9.9999990), "    -9.9999990");
+    assert_eq!(format_flo32(-10.0), "    -10.000000");
+    assert_eq!(format_flo32(-99.999977), "    -99.999977");
+    assert_eq!(format_flo32(-99.999992), "    -99.999992");
+    assert_eq!(format_flo32(-100.0), "    -100.00000");
+    assert_eq!(format_flo32(-999.99994), "    -999.99994");
+    assert_eq!(format_flo32(-1000.0), "    -1000.0000");
+    assert_eq!(format_flo32(-9999.9990), "    -9999.9990");
+    assert_eq!(format_flo32(-10000.0), "    -10000.000");
+    assert_eq!(format_flo32(-99999.992), "    -99999.992");
+    assert_eq!(format_flo32(-100000.0), "    -100000.00");
+    assert_eq!(format_flo32(-999999.94), "    -999999.94");
+    assert_eq!(format_flo32(-1000000.0), "    -1000000.0");
+    assert_eq!(format_flo32(-9999999.0), "    -9999999.0");
+    assert_eq!(format_flo32(-10000000.0), "     -10000000");
+    assert_eq!(format_flo32(-99999992.0), "     -99999992");
+    assert_eq!(format_flo32(-100000000.0), "  -1.0000000e8");
+    assert_eq!(format_flo32(-9.9999994e8), "  -9.9999994e8");
+    assert_eq!(format_flo32(-1.0e9), "  -1.0000000e9");
+    assert_eq!(format_flo32(-9.9999990e9), "  -9.9999990e9");
+    assert_eq!(format_flo32(-1.0e10), " -1.0000000e10");
+
+    assert_eq!(format_flo32(-0.1), "   -0.10000000");
+    assert_eq!(format_flo32(-0.99999994), "   -0.99999994");
+    assert_eq!(format_flo32(-0.010000001), " -1.0000001e-2");
+    assert_eq!(format_flo32(-0.099999994), " -9.9999994e-2");
+    assert_eq!(format_flo32(-0.001), " -1.0000000e-3");
+    assert_eq!(format_flo32(-0.0099999998), " -9.9999998e-3");
+
+    assert_eq!(format_flo32(3.4028233e38), "  3.4028233e38");
+    assert_eq!(format_flo32(-3.4028233e38), " -3.4028233e38");
+    assert_eq!(format_flo32(-1.1663108e-38), "-1.1663108e-38");
+    assert_eq!(format_flo32(-4.7019771e-38), "-4.7019771e-38");
+    assert_eq!(format_flo32(1e-45), "         1e-45");
+
+    assert_eq!(format_flo32(-3.402823466e+38), " -3.4028235e38");
+    assert_eq!(format_flo32(f32::NAN), "           NaN");
+    assert_eq!(format_flo32(f32::INFINITY), "           inf");
+    assert_eq!(format_flo32(f32::NEG_INFINITY), "          -inf");
+    assert_eq!(format_flo32(-0.0), "            -0");
+    assert_eq!(format_flo32(0.0), "             0");
+}
+
+#[test]
+fn test_format_flo64() {
+    assert_eq!(format_flo64(1.0), "      1.0000000000000000");
+    assert_eq!(format_flo64(10.0), "      10.000000000000000");
+    assert_eq!(format_flo64(1000000000000000.0), "      1000000000000000.0");
+    assert_eq!(
+        format_flo64(10000000000000000.0),
+        "       10000000000000000"
+    );
+    assert_eq!(
+        format_flo64(100000000000000000.0),
+        "   1.0000000000000000e17"
+    );
+
+    assert_eq!(format_flo64(-0.1), "    -0.10000000000000001");
+    assert_eq!(format_flo64(-0.01), "  -1.0000000000000000e-2");
+
+    assert_eq!(
+        format_flo64(-2.2250738585072014e-308),
+        "-2.2250738585072014e-308"
+    );
+    assert_eq!(format_flo64(4e-320), "                  4e-320");
+    assert_eq!(format_flo64(f64::NAN), "                     NaN");
+    assert_eq!(format_flo64(f64::INFINITY), "                     inf");
+    assert_eq!(format_flo64(f64::NEG_INFINITY), "                    -inf");
+    assert_eq!(format_flo64(-0.0), "                      -0");
+    assert_eq!(format_flo64(0.0), "                       0");
+}
+
+#[test]
+fn test_format_flo16() {
+    assert_eq!(format_flo16(f16::from_bits(0x8400u16)), "-6.104e-5");
+    assert_eq!(format_flo16(f16::from_bits(0x8401u16)), "-6.109e-5");
+    assert_eq!(format_flo16(f16::from_bits(0x8402u16)), "-6.115e-5");
+    assert_eq!(format_flo16(f16::from_bits(0x8403u16)), "-6.121e-5");
+
+    assert_eq!(format_flo16(f16::from_f32(1.0)), "    1.000");
+    assert_eq!(format_flo16(f16::from_f32(10.0)), "    10.00");
+    assert_eq!(format_flo16(f16::from_f32(100.0)), "    100.0");
+    assert_eq!(format_flo16(f16::from_f32(1000.0)), "     1000");
+    assert_eq!(format_flo16(f16::from_f32(10000.0)), "  1.000e4");
+
+    assert_eq!(format_flo16(f16::from_f32(-0.2)), "  -0.2000");
+    assert_eq!(format_flo16(f16::from_f32(-0.02)), "-2.000e-2");
+
+    assert_eq!(format_flo16(f16::MIN_POSITIVE_SUBNORMAL), " 5.960e-8");
+    assert_eq!(format_flo16(f16::MIN), " -6.550e4");
+    assert_eq!(format_flo16(f16::NAN), "      NaN");
+    assert_eq!(format_flo16(f16::INFINITY), "      inf");
+    assert_eq!(format_flo16(f16::NEG_INFINITY), "     -inf");
+    assert_eq!(format_flo16(f16::NEG_ZERO), "       -0");
+    assert_eq!(format_flo16(f16::ZERO), "        0");
+}
+
+
\ No newline at end of file diff --git a/src/uu_od/prn_int.rs.html b/src/uu_od/prn_int.rs.html new file mode 100644 index 000000000..d29b2b848 --- /dev/null +++ b/src/uu_od/prn_int.rs.html @@ -0,0 +1,399 @@ +prn_int.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+
+use crate::formatteriteminfo::*;
+
+/// format string to print octal using `int_writer_unsigned`
+macro_rules! OCT {
+    () => {
+        " {:0width$o}"
+    };
+}
+/// format string to print hexadecimal using `int_writer_unsigned`
+macro_rules! HEX {
+    () => {
+        " {:0width$x}"
+    };
+}
+/// format string to print decimal using `int_writer_unsigned` or `int_writer_signed`
+macro_rules! DEC {
+    () => {
+        " {:width$}"
+    };
+}
+
+/// defines a static struct of type `FormatterItemInfo` called `$NAME`
+///
+/// Used to format unsigned integer types with help of a function called `$function`
+/// `$byte_size` is the size of the type, `$print_width` is the maximum width in
+/// human-readable format. `$format_str` is one of OCT, HEX or DEC
+macro_rules! int_writer_unsigned {
+    ($NAME:ident, $byte_size:expr, $print_width:expr, $function:ident, $format_str:expr) => {
+        fn $function(p: u64) -> String {
+            format!($format_str, p, width = $print_width - 1)
+        }
+
+        pub static $NAME: FormatterItemInfo = FormatterItemInfo {
+            byte_size: $byte_size,
+            print_width: $print_width,
+            formatter: FormatWriter::IntWriter($function),
+        };
+    };
+}
+
+/// defines a static struct of type `FormatterItemInfo` called `$NAME`
+///
+/// Used to format signed integer types with help of a function called `$function`
+/// `$byte_size` is the size of the type, `$print_width` is the maximum width in
+/// human-readable format. `$format_str` should be DEC
+macro_rules! int_writer_signed {
+    ($NAME:ident, $byte_size:expr, $print_width:expr, $function:ident, $format_str:expr) => {
+        fn $function(p: u64) -> String {
+            let s = sign_extend(p, $byte_size);
+            format!($format_str, s, width = $print_width - 1)
+        }
+
+        pub static $NAME: FormatterItemInfo = FormatterItemInfo {
+            byte_size: $byte_size,
+            print_width: $print_width,
+            formatter: FormatWriter::IntWriter($function),
+        };
+    };
+}
+
+/// Extends a signed number in `item` of `item_bytes` bytes into a (signed) i64
+fn sign_extend(item: u64, item_bytes: usize) -> i64 {
+    let shift = 64 - item_bytes * 8;
+    (item << shift) as i64 >> shift
+}
+
+int_writer_unsigned!(FORMAT_ITEM_OCT8, 1, 4, format_item_oct8, OCT!()); // max: 377
+int_writer_unsigned!(FORMAT_ITEM_OCT16, 2, 7, format_item_oct16, OCT!()); // max: 177777
+int_writer_unsigned!(FORMAT_ITEM_OCT32, 4, 12, format_item_oct32, OCT!()); // max: 37777777777
+int_writer_unsigned!(FORMAT_ITEM_OCT64, 8, 23, format_item_oct64, OCT!()); // max: 1777777777777777777777
+
+int_writer_unsigned!(FORMAT_ITEM_HEX8, 1, 3, format_item_hex8, HEX!()); // max: ff
+int_writer_unsigned!(FORMAT_ITEM_HEX16, 2, 5, format_item_hex16, HEX!()); // max: ffff
+int_writer_unsigned!(FORMAT_ITEM_HEX32, 4, 9, format_item_hex32, HEX!()); // max: ffffffff
+int_writer_unsigned!(FORMAT_ITEM_HEX64, 8, 17, format_item_hex64, HEX!()); // max: ffffffffffffffff
+
+int_writer_unsigned!(FORMAT_ITEM_DEC8U, 1, 4, format_item_dec_u8, DEC!()); // max: 255
+int_writer_unsigned!(FORMAT_ITEM_DEC16U, 2, 6, format_item_dec_u16, DEC!()); // max: 65535
+int_writer_unsigned!(FORMAT_ITEM_DEC32U, 4, 11, format_item_dec_u32, DEC!()); // max: 4294967295
+int_writer_unsigned!(FORMAT_ITEM_DEC64U, 8, 21, format_item_dec_u64, DEC!()); // max: 18446744073709551615
+
+int_writer_signed!(FORMAT_ITEM_DEC8S, 1, 5, format_item_dec_s8, DEC!()); // max: -128
+int_writer_signed!(FORMAT_ITEM_DEC16S, 2, 7, format_item_dec_s16, DEC!()); // max: -32768
+int_writer_signed!(FORMAT_ITEM_DEC32S, 4, 12, format_item_dec_s32, DEC!()); // max: -2147483648
+int_writer_signed!(FORMAT_ITEM_DEC64S, 8, 21, format_item_dec_s64, DEC!()); // max: -9223372036854775808
+
+#[test]
+fn test_sign_extend() {
+    assert_eq!(
+        0xffff_ffff_ffff_ff80u64 as i64,
+        sign_extend(0x0000_0000_0000_0080, 1)
+    );
+    assert_eq!(
+        0xffff_ffff_ffff_8000u64 as i64,
+        sign_extend(0x0000_0000_0000_8000, 2)
+    );
+    assert_eq!(
+        0xffff_ffff_ff80_0000u64 as i64,
+        sign_extend(0x0000_0000_0080_0000, 3)
+    );
+    assert_eq!(
+        0xffff_ffff_8000_0000u64 as i64,
+        sign_extend(0x0000_0000_8000_0000, 4)
+    );
+    assert_eq!(
+        0xffff_ff80_0000_0000u64 as i64,
+        sign_extend(0x0000_0080_0000_0000, 5)
+    );
+    assert_eq!(
+        0xffff_8000_0000_0000u64 as i64,
+        sign_extend(0x0000_8000_0000_0000, 6)
+    );
+    assert_eq!(
+        0xff80_0000_0000_0000u64 as i64,
+        sign_extend(0x0080_0000_0000_0000, 7)
+    );
+    assert_eq!(
+        0x8000_0000_0000_0000u64 as i64,
+        sign_extend(0x8000_0000_0000_0000, 8)
+    );
+
+    assert_eq!(0x0000_0000_0000_007f, sign_extend(0x0000_0000_0000_007f, 1));
+    assert_eq!(0x0000_0000_0000_7fff, sign_extend(0x0000_0000_0000_7fff, 2));
+    assert_eq!(0x0000_0000_007f_ffff, sign_extend(0x0000_0000_007f_ffff, 3));
+    assert_eq!(0x0000_0000_7fff_ffff, sign_extend(0x0000_0000_7fff_ffff, 4));
+    assert_eq!(0x0000_007f_ffff_ffff, sign_extend(0x0000_007f_ffff_ffff, 5));
+    assert_eq!(0x0000_7fff_ffff_ffff, sign_extend(0x0000_7fff_ffff_ffff, 6));
+    assert_eq!(0x007f_ffff_ffff_ffff, sign_extend(0x007f_ffff_ffff_ffff, 7));
+    assert_eq!(0x7fff_ffff_ffff_ffff, sign_extend(0x7fff_ffff_ffff_ffff, 8));
+}
+
+#[test]
+fn test_format_item_oct() {
+    assert_eq!(" 000", format_item_oct8(0));
+    assert_eq!(" 377", format_item_oct8(0xff));
+    assert_eq!(" 000000", format_item_oct16(0));
+    assert_eq!(" 177777", format_item_oct16(0xffff));
+    assert_eq!(" 00000000000", format_item_oct32(0));
+    assert_eq!(" 37777777777", format_item_oct32(0xffff_ffff));
+    assert_eq!(" 0000000000000000000000", format_item_oct64(0));
+    assert_eq!(
+        " 1777777777777777777777",
+        format_item_oct64(0xffff_ffff_ffff_ffff)
+    );
+}
+
+#[test]
+fn test_format_item_hex() {
+    assert_eq!(" 00", format_item_hex8(0));
+    assert_eq!(" ff", format_item_hex8(0xff));
+    assert_eq!(" 0000", format_item_hex16(0));
+    assert_eq!(" ffff", format_item_hex16(0xffff));
+    assert_eq!(" 00000000", format_item_hex32(0));
+    assert_eq!(" ffffffff", format_item_hex32(0xffff_ffff));
+    assert_eq!(" 0000000000000000", format_item_hex64(0));
+    assert_eq!(
+        " ffffffffffffffff",
+        format_item_hex64(0xffff_ffff_ffff_ffff)
+    );
+}
+
+#[test]
+fn test_format_item_dec_u() {
+    assert_eq!("   0", format_item_dec_u8(0));
+    assert_eq!(" 255", format_item_dec_u8(0xff));
+    assert_eq!("     0", format_item_dec_u16(0));
+    assert_eq!(" 65535", format_item_dec_u16(0xffff));
+    assert_eq!("          0", format_item_dec_u32(0));
+    assert_eq!(" 4294967295", format_item_dec_u32(0xffff_ffff));
+    assert_eq!("                    0", format_item_dec_u64(0));
+    assert_eq!(
+        " 18446744073709551615",
+        format_item_dec_u64(0xffff_ffff_ffff_ffff)
+    );
+}
+
+#[test]
+fn test_format_item_dec_s() {
+    assert_eq!("    0", format_item_dec_s8(0));
+    assert_eq!("  127", format_item_dec_s8(0x7f));
+    assert_eq!(" -128", format_item_dec_s8(0x80));
+    assert_eq!("      0", format_item_dec_s16(0));
+    assert_eq!("  32767", format_item_dec_s16(0x7fff));
+    assert_eq!(" -32768", format_item_dec_s16(0x8000));
+    assert_eq!("           0", format_item_dec_s32(0));
+    assert_eq!("  2147483647", format_item_dec_s32(0x7fff_ffff));
+    assert_eq!(" -2147483648", format_item_dec_s32(0x8000_0000));
+    assert_eq!("                    0", format_item_dec_s64(0));
+    assert_eq!(
+        "  9223372036854775807",
+        format_item_dec_s64(0x7fff_ffff_ffff_ffff)
+    );
+    assert_eq!(
+        " -9223372036854775808",
+        format_item_dec_s64(0x8000_0000_0000_0000)
+    );
+}
+
+
\ No newline at end of file diff --git a/src/uu_paste/paste.rs.html b/src/uu_paste/paste.rs.html new file mode 100644 index 000000000..98cd5d480 --- /dev/null +++ b/src/uu_paste/paste.rs.html @@ -0,0 +1,315 @@ +paste.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) delim
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{stdin, BufRead, BufReader, Read};
+use std::iter::repeat;
+use std::path::Path;
+
+static ABOUT: &str = "Write lines consisting of the sequentially corresponding lines from each
+FILE, separated by TABs, to standard output.";
+
+mod options {
+    pub const DELIMITER: &str = "delimiters";
+    pub const SERIAL: &str = "serial";
+    pub const FILE: &str = "file";
+}
+
+// Wraps BufReader and stdin
+fn read_line<R: Read>(
+    reader: Option<&mut BufReader<R>>,
+    buf: &mut String,
+) -> std::io::Result<usize> {
+    match reader {
+        Some(reader) => reader.read_line(buf),
+        None => stdin().read_line(buf),
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let matches = uu_app().get_matches_from(args);
+
+    let serial = matches.is_present(options::SERIAL);
+    let delimiters = matches.value_of(options::DELIMITER).unwrap().to_owned();
+    let files = matches
+        .values_of(options::FILE)
+        .unwrap()
+        .map(|s| s.to_owned())
+        .collect();
+    paste(files, serial, delimiters);
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::SERIAL)
+                .long(options::SERIAL)
+                .short("s")
+                .help("paste one file at a time instead of in parallel"),
+        )
+        .arg(
+            Arg::with_name(options::DELIMITER)
+                .long(options::DELIMITER)
+                .short("d")
+                .help("reuse characters from LIST instead of TABs")
+                .value_name("LIST")
+                .default_value("\t")
+                .hide_default_value(true),
+        )
+        .arg(
+            Arg::with_name(options::FILE)
+                .value_name("FILE")
+                .multiple(true)
+                .default_value("-"),
+        )
+}
+
+fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
+    let mut files: Vec<_> = filenames
+        .into_iter()
+        .map(|name| {
+            if name == "-" {
+                None
+            } else {
+                let r = crash_if_err!(1, File::open(Path::new(&name)));
+                Some(BufReader::new(r))
+            }
+        })
+        .collect();
+
+    let delimiters: Vec<String> = unescape(delimiters)
+        .chars()
+        .map(|x| x.to_string())
+        .collect();
+    let mut delim_count = 0;
+
+    if serial {
+        for file in &mut files {
+            let mut output = String::new();
+            loop {
+                let mut line = String::new();
+                match read_line(file.as_mut(), &mut line) {
+                    Ok(0) => break,
+                    Ok(_) => {
+                        output.push_str(line.trim_end());
+                        output.push_str(&delimiters[delim_count % delimiters.len()]);
+                    }
+                    Err(e) => crash!(1, "{}", e.to_string()),
+                }
+                delim_count += 1;
+            }
+            println!("{}", &output[..output.len() - 1]);
+        }
+    } else {
+        let mut eof: Vec<bool> = repeat(false).take(files.len()).collect();
+        loop {
+            let mut output = String::new();
+            let mut eof_count = 0;
+            for (i, file) in files.iter_mut().enumerate() {
+                if eof[i] {
+                    eof_count += 1;
+                } else {
+                    let mut line = String::new();
+                    match read_line(file.as_mut(), &mut line) {
+                        Ok(0) => {
+                            eof[i] = true;
+                            eof_count += 1;
+                        }
+                        Ok(_) => output.push_str(line.trim_end()),
+                        Err(e) => crash!(1, "{}", e.to_string()),
+                    }
+                }
+                output.push_str(&delimiters[delim_count % delimiters.len()]);
+                delim_count += 1;
+            }
+            if files.len() == eof_count {
+                break;
+            }
+            println!("{}", &output[..output.len() - 1]);
+            delim_count = 0;
+        }
+    }
+}
+
+// Unescape all special characters
+// TODO: this will need work to conform to GNU implementation
+fn unescape(s: String) -> String {
+    s.replace("\\n", "\n")
+        .replace("\\t", "\t")
+        .replace("\\\\", "\\")
+        .replace("\\", "")
+}
+
+
\ No newline at end of file diff --git a/src/uu_pathchk/pathchk.rs.html b/src/uu_pathchk/pathchk.rs.html new file mode 100644 index 000000000..cab1073a6 --- /dev/null +++ b/src/uu_pathchk/pathchk.rs.html @@ -0,0 +1,519 @@ +pathchk.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+
+#![allow(unused_must_use)] // because we of writeln!
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Inokentiy Babushkin <inokentiy.babushkin@googlemail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE file
+//  * that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) lstat
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs;
+use std::io::{ErrorKind, Write};
+use uucore::InvalidEncodingHandling;
+
+// operating mode
+enum Mode {
+    Default, // use filesystem to determine information and limits
+    Basic,   // check basic compatibility with POSIX
+    Extra,   // check for leading dashes and empty names
+    Both,    // a combination of `Basic` and `Extra`
+}
+
+static ABOUT: &str = "Check whether file names are valid or portable";
+
+mod options {
+    pub const POSIX: &str = "posix";
+    pub const POSIX_SPECIAL: &str = "posix-special";
+    pub const PORTABILITY: &str = "portability";
+    pub const PATH: &str = "path";
+}
+
+// a few global constants as used in the GNU implementation
+const POSIX_PATH_MAX: usize = 256;
+const POSIX_NAME_MAX: usize = 14;
+
+fn usage() -> String {
+    format!("{0} [OPTION]... NAME...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    // set working mode
+    let is_posix = matches.values_of(options::POSIX).is_some();
+    let is_posix_special = matches.values_of(options::POSIX_SPECIAL).is_some();
+    let is_portability = matches.values_of(options::PORTABILITY).is_some();
+
+    let mode = if (is_posix && is_posix_special) || is_portability {
+        Mode::Both
+    } else if is_posix {
+        Mode::Basic
+    } else if is_posix_special {
+        Mode::Extra
+    } else {
+        Mode::Default
+    };
+
+    // take necessary actions
+    let paths = matches.values_of(options::PATH);
+    let mut res = if paths.is_none() {
+        show_error!(
+            "missing operand\nTry '{} --help' for more information",
+            uucore::execution_phrase()
+        );
+        false
+    } else {
+        true
+    };
+
+    if res {
+        // free strings are path operands
+        // FIXME: TCS, seems inefficient and overly verbose (?)
+        for p in paths.unwrap() {
+            let mut path = Vec::new();
+            for path_segment in p.split('/') {
+                path.push(path_segment.to_string());
+            }
+            res &= check_path(&mode, &path);
+        }
+    }
+
+    // determine error code
+    if res {
+        0
+    } else {
+        1
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::POSIX)
+                .short("p")
+                .help("check for most POSIX systems"),
+        )
+        .arg(
+            Arg::with_name(options::POSIX_SPECIAL)
+                .short("P")
+                .help(r#"check for empty names and leading "-""#),
+        )
+        .arg(
+            Arg::with_name(options::PORTABILITY)
+                .long(options::PORTABILITY)
+                .help("check for all POSIX systems (equivalent to -p -P)"),
+        )
+        .arg(Arg::with_name(options::PATH).hidden(true).multiple(true))
+}
+
+// check a path, given as a slice of it's components and an operating mode
+fn check_path(mode: &Mode, path: &[String]) -> bool {
+    match *mode {
+        Mode::Basic => check_basic(path),
+        Mode::Extra => check_default(path) && check_extra(path),
+        Mode::Both => check_basic(path) && check_extra(path),
+        _ => check_default(path),
+    }
+}
+
+// check a path in basic compatibility mode
+fn check_basic(path: &[String]) -> bool {
+    let joined_path = path.join("/");
+    let total_len = joined_path.len();
+    // path length
+    if total_len > POSIX_PATH_MAX {
+        writeln!(
+            &mut std::io::stderr(),
+            "limit {} exceeded by length {} of file name {}",
+            POSIX_PATH_MAX,
+            total_len,
+            joined_path
+        );
+        return false;
+    } else if total_len == 0 {
+        writeln!(&mut std::io::stderr(), "empty file name");
+        return false;
+    }
+    // components: character portability and length
+    for p in path {
+        let component_len = p.len();
+        if component_len > POSIX_NAME_MAX {
+            writeln!(
+                &mut std::io::stderr(),
+                "limit {} exceeded by length {} of file name component '{}'",
+                POSIX_NAME_MAX,
+                component_len,
+                p
+            );
+            return false;
+        }
+        if !check_portable_chars(p) {
+            return false;
+        }
+    }
+    // permission checks
+    check_searchable(&joined_path)
+}
+
+// check a path in extra compatibility mode
+fn check_extra(path: &[String]) -> bool {
+    // components: leading hyphens
+    for p in path {
+        if p.starts_with('-') {
+            writeln!(
+                &mut std::io::stderr(),
+                "leading hyphen in file name component '{}'",
+                p
+            );
+            return false;
+        }
+    }
+    // path length
+    if path.join("/").is_empty() {
+        writeln!(&mut std::io::stderr(), "empty file name");
+        return false;
+    }
+    true
+}
+
+// check a path in default mode (using the file system)
+fn check_default(path: &[String]) -> bool {
+    let joined_path = path.join("/");
+    let total_len = joined_path.len();
+    // path length
+    if total_len > libc::PATH_MAX as usize {
+        writeln!(
+            &mut std::io::stderr(),
+            "limit {} exceeded by length {} of file name '{}'",
+            libc::PATH_MAX,
+            total_len,
+            joined_path
+        );
+        return false;
+    }
+    // components: length
+    for p in path {
+        let component_len = p.len();
+        if component_len > libc::FILENAME_MAX as usize {
+            writeln!(
+                &mut std::io::stderr(),
+                "limit {} exceeded by length {} of file name component '{}'",
+                libc::FILENAME_MAX,
+                component_len,
+                p
+            );
+            return false;
+        }
+    }
+    // permission checks
+    check_searchable(&joined_path)
+}
+
+// check whether a path is or if other problems arise
+fn check_searchable(path: &str) -> bool {
+    // we use lstat, just like the original implementation
+    match fs::symlink_metadata(path) {
+        Ok(_) => true,
+        Err(e) => {
+            if e.kind() == ErrorKind::NotFound {
+                true
+            } else {
+                writeln!(&mut std::io::stderr(), "{}", e);
+                false
+            }
+        }
+    }
+}
+
+// check whether a path segment contains only valid (read: portable) characters
+fn check_portable_chars(path_segment: &str) -> bool {
+    const VALID_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-";
+    for (i, ch) in path_segment.as_bytes().iter().enumerate() {
+        if !VALID_CHARS.contains(ch) {
+            let invalid = path_segment[i..].chars().next().unwrap();
+            writeln!(
+                &mut std::io::stderr(),
+                "nonportable character '{}' in file name component '{}'",
+                invalid,
+                path_segment
+            );
+            return false;
+        }
+    }
+    true
+}
+
+
\ No newline at end of file diff --git a/src/uu_pinky/pinky.rs.html b/src/uu_pinky/pinky.rs.html new file mode 100644 index 000000000..8b603b7d6 --- /dev/null +++ b/src/uu_pinky/pinky.rs.html @@ -0,0 +1,757 @@ +pinky.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) BUFSIZE gecos fullname, mesg iobuf
+
+#[macro_use]
+extern crate uucore;
+use uucore::entries::{Locate, Passwd};
+use uucore::libc::S_IWGRP;
+use uucore::utmpx::{self, time, Utmpx};
+
+use std::io::prelude::*;
+use std::io::BufReader;
+
+use std::fs::File;
+use std::os::unix::fs::MetadataExt;
+
+use clap::{crate_version, App, Arg};
+use std::path::PathBuf;
+use uucore::InvalidEncodingHandling;
+
+const BUFSIZE: usize = 1024;
+
+static ABOUT: &str = "pinky - lightweight finger";
+
+mod options {
+    pub const LONG_FORMAT: &str = "long_format";
+    pub const OMIT_HOME_DIR: &str = "omit_home_dir";
+    pub const OMIT_PROJECT_FILE: &str = "omit_project_file";
+    pub const OMIT_PLAN_FILE: &str = "omit_plan_file";
+    pub const SHORT_FORMAT: &str = "short_format";
+    pub const OMIT_HEADINGS: &str = "omit_headings";
+    pub const OMIT_NAME: &str = "omit_name";
+    pub const OMIT_NAME_HOST: &str = "omit_name_host";
+    pub const OMIT_NAME_HOST_TIME: &str = "omit_name_host_time";
+    pub const USER: &str = "user";
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [USER]...", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    format!(
+        "A lightweight 'finger' program;  print user information.\n\
+         The utmp file will be {}.",
+        utmpx::DEFAULT_FILE
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+    let after_help = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let users: Vec<String> = matches
+        .values_of(options::USER)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    // If true, display the hours:minutes since each user has touched
+    // the keyboard, or blank if within the last minute, or days followed
+    // by a 'd' if not within the last day.
+    let mut include_idle = true;
+
+    // If true, display a line at the top describing each field.
+    let include_heading = !matches.is_present(options::OMIT_HEADINGS);
+
+    // if true, display the user's full name from pw_gecos.
+    let mut include_fullname = true;
+
+    // if true, display the user's ~/.project file when doing long format.
+    let include_project = !matches.is_present(options::OMIT_PROJECT_FILE);
+
+    // if true, display the user's ~/.plan file when doing long format.
+    let include_plan = !matches.is_present(options::OMIT_PLAN_FILE);
+
+    // if true, display the user's home directory and shell
+    // when doing long format.
+    let include_home_and_shell = !matches.is_present(options::OMIT_HOME_DIR);
+
+    // if true, use the "short" output format.
+    let do_short_format = !matches.is_present(options::LONG_FORMAT);
+
+    /* if true, display the ut_host field. */
+    let mut include_where = true;
+
+    if matches.is_present(options::OMIT_NAME) {
+        include_fullname = false;
+    }
+    if matches.is_present(options::OMIT_NAME_HOST) {
+        include_fullname = false;
+        include_where = false;
+    }
+    if matches.is_present(options::OMIT_NAME_HOST_TIME) {
+        include_fullname = false;
+        include_idle = false;
+        include_where = false;
+    }
+
+    let pk = Pinky {
+        include_idle,
+        include_heading,
+        include_fullname,
+        include_project,
+        include_plan,
+        include_home_and_shell,
+        include_where,
+        names: users,
+    };
+
+    if do_short_format {
+        pk.short_pinky();
+        0
+    } else {
+        pk.long_pinky()
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::LONG_FORMAT)
+                .short("l")
+                .requires(options::USER)
+                .help("produce long format output for the specified USERs"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_HOME_DIR)
+                .short("b")
+                .help("omit the user's home directory and shell in long format"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_PROJECT_FILE)
+                .short("h")
+                .help("omit the user's project file in long format"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_PLAN_FILE)
+                .short("p")
+                .help("omit the user's plan file in long format"),
+        )
+        .arg(
+            Arg::with_name(options::SHORT_FORMAT)
+                .short("s")
+                .help("do short format output, this is the default"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_HEADINGS)
+                .short("f")
+                .help("omit the line of column headings in short format"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_NAME)
+                .short("w")
+                .help("omit the user's full name in short format"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_NAME_HOST)
+                .short("i")
+                .help("omit the user's full name and remote host in short format"),
+        )
+        .arg(
+            Arg::with_name(options::OMIT_NAME_HOST_TIME)
+                .short("q")
+                .help("omit the user's full name, remote host and idle time in short format"),
+        )
+        .arg(
+            Arg::with_name(options::USER)
+                .takes_value(true)
+                .multiple(true),
+        )
+}
+
+struct Pinky {
+    include_idle: bool,
+    include_heading: bool,
+    include_fullname: bool,
+    include_project: bool,
+    include_plan: bool,
+    include_where: bool,
+    include_home_and_shell: bool,
+    names: Vec<String>,
+}
+
+pub trait Capitalize {
+    fn capitalize(&self) -> String;
+}
+
+impl Capitalize for str {
+    fn capitalize(&self) -> String {
+        self.char_indices()
+            .fold(String::with_capacity(self.len()), |mut acc, x| {
+                if x.0 != 0 {
+                    acc.push(x.1)
+                } else {
+                    acc.push(x.1.to_ascii_uppercase())
+                }
+                acc
+            })
+    }
+}
+
+fn idle_string(when: i64) -> String {
+    thread_local! {
+        static NOW: time::Tm = time::now()
+    }
+    NOW.with(|n| {
+        let duration = n.to_timespec().sec - when;
+        if duration < 60 {
+            // less than 1min
+            "     ".to_owned()
+        } else if duration < 24 * 3600 {
+            // less than 1day
+            let hours = duration / (60 * 60);
+            let minutes = (duration % (60 * 60)) / 60;
+            format!("{:02}:{:02}", hours, minutes)
+        } else {
+            // more than 1day
+            let days = duration / (24 * 3600);
+            format!("{}d", days)
+        }
+    })
+}
+
+fn time_string(ut: &Utmpx) -> String {
+    time::strftime("%b %e %H:%M", &ut.login_time()).unwrap() // LC_ALL=C
+}
+
+impl Pinky {
+    fn print_entry(&self, ut: &Utmpx) {
+        let mut pts_path = PathBuf::from("/dev");
+        pts_path.push(ut.tty_device().as_str());
+
+        let mesg;
+        let last_change;
+        match pts_path.metadata() {
+            Ok(meta) => {
+                mesg = if meta.mode() & (S_IWGRP as u32) != 0 {
+                    ' '
+                } else {
+                    '*'
+                };
+                last_change = meta.atime();
+            }
+            _ => {
+                mesg = '?';
+                last_change = 0;
+            }
+        }
+
+        print!("{1:<8.0$}", utmpx::UT_NAMESIZE, ut.user());
+
+        if self.include_fullname {
+            if let Ok(pw) = Passwd::locate(ut.user().as_ref()) {
+                let mut gecos = pw.user_info().into_owned();
+                if let Some(n) = gecos.find(',') {
+                    gecos.truncate(n + 1);
+                }
+                print!(" {:<19.19}", gecos.replace("&", &pw.name().capitalize()));
+            } else {
+                print!(" {:19}", "        ???");
+            }
+        }
+
+        print!(" {}{:<8.*}", mesg, utmpx::UT_LINESIZE, ut.tty_device());
+
+        if self.include_idle {
+            if last_change != 0 {
+                print!(" {:<6}", idle_string(last_change));
+            } else {
+                print!(" {:<6}", "?????");
+            }
+        }
+
+        print!(" {}", time_string(ut));
+
+        let mut s = ut.host();
+        if self.include_where && !s.is_empty() {
+            s = safe_unwrap!(ut.canon_host());
+            print!(" {}", s);
+        }
+
+        println!();
+    }
+
+    fn print_heading(&self) {
+        print!("{:<8}", "Login");
+        if self.include_fullname {
+            print!(" {:<19}", "Name");
+        }
+        print!(" {:<9}", " TTY");
+        if self.include_idle {
+            print!(" {:<6}", "Idle");
+        }
+        print!(" {:<16}", "When");
+        if self.include_where {
+            print!(" Where");
+        }
+        println!();
+    }
+
+    fn short_pinky(&self) {
+        if self.include_heading {
+            self.print_heading();
+        }
+        for ut in Utmpx::iter_all_records() {
+            if ut.is_user_process() {
+                if self.names.is_empty() {
+                    self.print_entry(&ut)
+                } else if self.names.iter().any(|n| n.as_str() == ut.user()) {
+                    self.print_entry(&ut);
+                }
+            }
+        }
+    }
+
+    fn long_pinky(&self) -> i32 {
+        for u in &self.names {
+            print!("Login name: {:<28}In real life: ", u);
+            if let Ok(pw) = Passwd::locate(u.as_str()) {
+                println!(" {}", pw.user_info().replace("&", &pw.name().capitalize()));
+                if self.include_home_and_shell {
+                    print!("Directory: {:<29}", pw.user_dir());
+                    println!("Shell:  {}", pw.user_shell());
+                }
+                if self.include_project {
+                    let mut p = PathBuf::from(pw.user_dir().as_ref());
+                    p.push(".project");
+                    if let Ok(f) = File::open(p) {
+                        print!("Project: ");
+                        read_to_console(f);
+                    }
+                }
+                if self.include_plan {
+                    let mut p = PathBuf::from(pw.user_dir().as_ref());
+                    p.push(".plan");
+                    if let Ok(f) = File::open(p) {
+                        println!("Plan:");
+                        read_to_console(f);
+                    }
+                }
+                println!();
+            } else {
+                println!(" ???");
+            }
+        }
+        0
+    }
+}
+
+fn read_to_console<F: Read>(f: F) {
+    let mut reader = BufReader::new(f);
+    let mut iobuf = [0_u8; BUFSIZE];
+    while let Ok(n) = reader.read(&mut iobuf) {
+        if n == 0 {
+            break;
+        }
+        let s = String::from_utf8_lossy(&iobuf);
+        print!("{}", s);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_pr/pr.rs.html b/src/uu_pr/pr.rs.html new file mode 100644 index 000000000..9710d4943 --- /dev/null +++ b/src/uu_pr/pr.rs.html @@ -0,0 +1,2593 @@ +pr.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+
+#![crate_name = "uu_pr"]
+
+// This file is part of the uutils coreutils package.
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+//
+
+// spell-checker:ignore (ToDO) adFfmprt, kmerge
+
+#[macro_use]
+extern crate quick_error;
+
+use chrono::offset::Local;
+use chrono::DateTime;
+use getopts::Matches;
+use getopts::{HasArg, Occur};
+use itertools::Itertools;
+use quick_error::ResultExt;
+use regex::Regex;
+use std::convert::From;
+use std::fs::{metadata, File};
+use std::io::{stdin, stdout, BufRead, BufReader, Lines, Read, Stdout, Write};
+#[cfg(unix)]
+use std::os::unix::fs::FileTypeExt;
+
+type IOError = std::io::Error;
+
+const NAME: &str = "pr";
+const VERSION: &str = env!("CARGO_PKG_VERSION");
+const TAB: char = '\t';
+const LINES_PER_PAGE: usize = 66;
+const LINES_PER_PAGE_FOR_FORM_FEED: usize = 63;
+const HEADER_LINES_PER_PAGE: usize = 5;
+const TRAILER_LINES_PER_PAGE: usize = 5;
+const FILE_STDIN: &str = "-";
+const READ_BUFFER_SIZE: usize = 1024 * 64;
+const DEFAULT_COLUMN_WIDTH: usize = 72;
+const DEFAULT_COLUMN_WIDTH_WITH_S_OPTION: usize = 512;
+const DEFAULT_COLUMN_SEPARATOR: &char = &TAB;
+const FF: u8 = 0x0C_u8;
+
+mod options {
+    pub const STRING_HEADER_OPTION: &str = "h";
+    pub const DOUBLE_SPACE_OPTION: &str = "d";
+    pub const NUMBERING_MODE_OPTION: &str = "n";
+    pub const FIRST_LINE_NUMBER_OPTION: &str = "N";
+    pub const PAGE_RANGE_OPTION: &str = "pages";
+    pub const NO_HEADER_TRAILER_OPTION: &str = "t";
+    pub const PAGE_LENGTH_OPTION: &str = "l";
+    pub const SUPPRESS_PRINTING_ERROR: &str = "r";
+    pub const FORM_FEED_OPTION: &str = "F";
+    pub const FORM_FEED_OPTION_SMALL: &str = "f";
+    pub const COLUMN_WIDTH_OPTION: &str = "w";
+    pub const PAGE_WIDTH_OPTION: &str = "W";
+    pub const ACROSS_OPTION: &str = "a";
+    pub const COLUMN_OPTION: &str = "column";
+    pub const COLUMN_CHAR_SEPARATOR_OPTION: &str = "s";
+    pub const COLUMN_STRING_SEPARATOR_OPTION: &str = "S";
+    pub const MERGE_FILES_PRINT: &str = "m";
+    pub const OFFSET_SPACES_OPTION: &str = "o";
+    pub const JOIN_LINES_OPTION: &str = "J";
+}
+
+struct OutputOptions {
+    /// Line numbering mode
+    number: Option<NumberingMode>,
+    header: String,
+    double_space: bool,
+    line_separator: String,
+    content_line_separator: String,
+    last_modified_time: String,
+    start_page: usize,
+    end_page: Option<usize>,
+    display_header_and_trailer: bool,
+    content_lines_per_page: usize,
+    page_separator_char: String,
+    column_mode_options: Option<ColumnModeOptions>,
+    merge_files_print: Option<usize>,
+    offset_spaces: String,
+    form_feed_used: bool,
+    join_lines: bool,
+    col_sep_for_printing: String,
+    line_width: Option<usize>,
+}
+
+struct FileLine {
+    file_id: usize,
+    line_number: usize,
+    page_number: usize,
+    group_key: usize,
+    line_content: Result<String, IOError>,
+    form_feeds_after: usize,
+}
+
+struct ColumnModeOptions {
+    width: usize,
+    columns: usize,
+    column_separator: String,
+    across_mode: bool,
+}
+
+/// Line numbering mode
+struct NumberingMode {
+    width: usize,
+    separator: String,
+    first_number: usize,
+}
+
+impl Default for NumberingMode {
+    fn default() -> NumberingMode {
+        NumberingMode {
+            width: 5,
+            separator: TAB.to_string(),
+            first_number: 1,
+        }
+    }
+}
+
+impl Default for FileLine {
+    fn default() -> FileLine {
+        FileLine {
+            file_id: 0,
+            line_number: 0,
+            page_number: 0,
+            group_key: 0,
+            line_content: Ok(String::new()),
+            form_feeds_after: 0,
+        }
+    }
+}
+
+impl From<IOError> for PrError {
+    fn from(err: IOError) -> Self {
+        PrError::EncounteredErrors(err.to_string())
+    }
+}
+
+quick_error! {
+    #[derive(Debug)]
+    enum PrError {
+        Input(err: IOError, path: String) {
+            context(path: &'a str, err: IOError) -> (err, path.to_owned())
+            display("pr: Reading from input {0} gave error", path)
+            source(err)
+        }
+
+        UnknownFiletype(path: String) {
+            display("pr: {0}: unknown filetype", path)
+        }
+
+        EncounteredErrors(msg: String) {
+            display("pr: {0}", msg)
+        }
+
+        IsDirectory(path: String) {
+            display("pr: {0}: Is a directory", path)
+        }
+
+        IsSocket(path: String) {
+            display("pr: cannot open {}, Operation not supported on socket", path)
+        }
+
+        NotExists(path: String) {
+            display("pr: cannot open {}, No such file or directory", path)
+        }
+    }
+}
+
+pub fn uu_app() -> clap::App<'static, 'static> {
+    // TODO: migrate to clap to get more shell completions
+    clap::App::new(uucore::util_name())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(uucore::InvalidEncodingHandling::Ignore)
+        .accept_any();
+    let mut opts = getopts::Options::new();
+
+    opts.opt(
+        "",
+        options::PAGE_RANGE_OPTION,
+        "Begin and stop printing with page FIRST_PAGE[:LAST_PAGE]",
+        "FIRST_PAGE[:LAST_PAGE]",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::STRING_HEADER_OPTION,
+        "header",
+        "Use the string header to replace the file name \
+         in the header line.",
+        "STRING",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::DOUBLE_SPACE_OPTION,
+        "double-space",
+        "Produce output that is double spaced. An extra <newline> character is output following every <newline>
+           found in the input.",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::NUMBERING_MODE_OPTION,
+        "number-lines",
+        "Provide width digit line numbering.  The default for width, if not specified, is 5.  The number occupies
+           the first width column positions of each text column or each line of -m output.  If char (any non-digit
+           character) is given, it is appended to the line number to separate it from whatever follows.  The default
+           for char is a <tab>.  Line numbers longer than width columns are truncated.",
+        "[char][width]",
+        HasArg::Maybe,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::FIRST_LINE_NUMBER_OPTION,
+        "first-line-number",
+        "start counting with NUMBER at 1st line of first page printed",
+        "NUMBER",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::NO_HEADER_TRAILER_OPTION,
+        "omit-header",
+        "Write neither the five-line identifying header nor the five-line trailer usually supplied for  each  page.  Quit
+              writing after the last line of each file without spacing to the end of the page.",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::PAGE_LENGTH_OPTION,
+        "length",
+        "Override the 66-line default (default number of lines of text 56, and with -F 63) and reset the page length to lines.  If lines is not greater than the sum  of  both
+              the  header  and trailer depths (in lines), the pr utility shall suppress both the header and trailer, as if the
+              -t option were in effect. ",
+        "lines",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::SUPPRESS_PRINTING_ERROR,
+        "no-file-warnings",
+        "omit warning when a file cannot be opened",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::FORM_FEED_OPTION,
+        "form-feed",
+        "Use a <form-feed> for new pages, instead of the default behavior that uses a sequence of <newline>s.",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+    opts.opt(
+        options::FORM_FEED_OPTION_SMALL,
+        "form-feed",
+        "Same as -F but pause before beginning the first page if standard output is a
+           terminal.",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        "",
+        options::COLUMN_OPTION,
+        "Produce multi-column output that is arranged in column columns (the default shall be 1) and is written down each
+              column  in  the order in which the text is received from the input file. This option should not be used with -m.
+              The options -e and -i shall be assumed for multiple text-column output.  Whether or not text columns are produced
+              with identical vertical lengths is unspecified, but a text column shall never exceed the length of the
+              page (see the -l option). When used with -t, use the minimum number of lines to write the output.",
+        "[column]",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::COLUMN_WIDTH_OPTION,
+        "width",
+        "Set the width of the line to width column positions for multiple text-column output only. If the -w option is
+              not specified and the -s option is not specified, the default width shall be 72. If the -w option is not specified
+              and the -s option is specified, the default width shall be 512.",
+        "[width]",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::PAGE_WIDTH_OPTION,
+        "page-width",
+        "set page width to PAGE_WIDTH (72) characters always,
+        truncate lines, except -J option is set, no interference
+        with -S or -s",
+        "[width]",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::ACROSS_OPTION,
+        "across",
+        "Modify the effect of the - column option so that the columns are filled across the page in a  round-robin  order
+              (for example, when column is 2, the first input line heads column 1, the second heads column 2, the third is the
+              second line in column 1, and so on).",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::COLUMN_CHAR_SEPARATOR_OPTION,
+        "separator",
+        "Separate text columns by the single character char instead of by the appropriate number of <space>s
+           (default for char is the <tab> character).",
+        "char",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::COLUMN_STRING_SEPARATOR_OPTION,
+        "sep-string",
+        "separate columns by STRING,
+        without -S: Default separator <TAB> with -J and <space>
+        otherwise (same as -S\" \"), no effect on column options",
+        "string",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::MERGE_FILES_PRINT,
+        "merge",
+        "Merge files. Standard output shall be formatted so the pr utility writes one line from each file specified by  a
+              file  operand, side by side into text columns of equal fixed widths, in terms of the number of column positions.
+              Implementations shall support merging of at least nine file operands.",
+        "",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::OFFSET_SPACES_OPTION,
+        "indent",
+        "Each  line of output shall be preceded by offset <space>s. If the -o option is not specified, the default offset
+              shall be zero. The space taken is in addition to the output line width (see the -w option below).",
+        "offset",
+        HasArg::Yes,
+        Occur::Optional,
+    );
+
+    opts.opt(
+        options::JOIN_LINES_OPTION,
+        "join-lines",
+        "merge full lines, turns off -W line truncation, no column
+    alignment, --sep-string[=STRING] sets separators",
+        "offset",
+        HasArg::No,
+        Occur::Optional,
+    );
+
+    opts.optflag("", "help", "display this help and exit");
+    opts.optflag("V", "version", "output version information and exit");
+
+    let opt_args = recreate_arguments(&args);
+
+    let matches = match opts.parse(&opt_args[1..]) {
+        Ok(m) => m,
+        Err(e) => panic!("Invalid options\n{}", e),
+    };
+
+    if matches.opt_present("version") {
+        println!("{} {}", NAME, VERSION);
+        return 0;
+    }
+
+    let mut files = matches.free.clone();
+    if files.is_empty() {
+        files.insert(0, FILE_STDIN.to_owned());
+    }
+
+    if matches.opt_present("help") {
+        return print_usage(&mut opts, &matches);
+    }
+
+    let file_groups: Vec<_> = if matches.opt_present(options::MERGE_FILES_PRINT) {
+        vec![files]
+    } else {
+        files.into_iter().map(|i| vec![i]).collect()
+    };
+
+    for file_group in file_groups {
+        let result_options = build_options(&matches, &file_group, args.join(" "));
+        let options = match result_options {
+            Ok(options) => options,
+            Err(err) => {
+                print_error(&matches, err);
+                return 1;
+            }
+        };
+
+        let cmd_result = if let Ok(group) = file_group.iter().exactly_one() {
+            pr(group, &options)
+        } else {
+            mpr(&file_group, &options)
+        };
+
+        let status = match cmd_result {
+            Err(error) => {
+                print_error(&matches, error);
+                1
+            }
+            _ => 0,
+        };
+        if status != 0 {
+            return status;
+        }
+    }
+
+    0
+}
+
+/// Returns re-written arguments which are passed to the program.
+/// Removes -column and +page option as getopts cannot parse things like -3 etc
+/// # Arguments
+/// * `args` - Command line arguments
+fn recreate_arguments(args: &[String]) -> Vec<String> {
+    let column_page_option = Regex::new(r"^[-+]\d+.*").unwrap();
+    let num_regex = Regex::new(r"(.\d+)|(\d+)|^[^-]$").unwrap();
+    //let a_file: Regex = Regex::new(r"^[^-+].*").unwrap();
+    let n_regex = Regex::new(r"^-n\s*$").unwrap();
+    let mut arguments = args.to_owned();
+    let num_option = args.iter().find_position(|x| n_regex.is_match(x.trim()));
+    if let Some((pos, _value)) = num_option {
+        if let Some(num_val_opt) = args.get(pos + 1) {
+            if !num_regex.is_match(num_val_opt) {
+                let could_be_file = arguments.remove(pos + 1);
+                arguments.insert(pos + 1, format!("{}", NumberingMode::default().width));
+                arguments.insert(pos + 2, could_be_file);
+            }
+        }
+    }
+
+    arguments
+        .into_iter()
+        .filter(|i| !column_page_option.is_match(i))
+        .collect()
+}
+
+fn print_error(matches: &Matches, err: PrError) {
+    if !matches.opt_present(options::SUPPRESS_PRINTING_ERROR) {
+        eprintln!("{}", err);
+    }
+}
+
+fn print_usage(opts: &mut getopts::Options, matches: &Matches) -> i32 {
+    println!("{} {} -- print files", NAME, VERSION);
+    println!();
+    println!(
+        "Usage: {} [+page] [-column] [-adFfmprt] [[-e] [char] [gap]]
+        [-L locale] [-h header] [[-i] [char] [gap]]
+        [-l lines] [-o offset] [[-s] [char]] [[-n] [char]
+        [width]] [-w width] [-] [file ...].",
+        NAME
+    );
+    println!();
+    let usage: &str = "The pr utility is a printing and pagination filter
+     for text files.  When multiple input files are specified,
+     each is read, formatted, and written to standard
+     output.  By default, the input is separated
+     into 66-line pages, each with
+
+     o   A 5-line header with the page number, date,
+         time, and the pathname of the file.
+
+     o   A 5-line trailer consisting of blank lines.
+
+     If standard output is associated with a terminal,
+     diagnostic messages are suppressed until the pr
+     utility has completed processing.
+
+     When multiple column output is specified, text columns
+     are of equal width.  By default text columns
+     are separated by at least one <blank>.  Input lines
+     that do not fit into a text column are truncated.
+     Lines are not truncated under single column output.";
+    println!("{}", opts.usage(usage));
+    println!("    +page \t\tBegin output at page number page of the formatted input.");
+    println!(
+        "    -column \t\tProduce multi-column output. Refer --{}",
+        options::COLUMN_OPTION
+    );
+    if matches.free.is_empty() {
+        return 1;
+    }
+
+    0
+}
+
+fn parse_usize(matches: &Matches, opt: &str) -> Option<Result<usize, PrError>> {
+    let from_parse_error_to_pr_error = |value_to_parse: (String, String)| {
+        let i = value_to_parse.0;
+        let option = value_to_parse.1;
+        i.parse().map_err(|_e| {
+            PrError::EncounteredErrors(format!("invalid {} argument '{}'", option, i))
+        })
+    };
+    matches
+        .opt_str(opt)
+        .map(|i| (i, format!("-{}", opt)))
+        .map(from_parse_error_to_pr_error)
+}
+
+fn build_options(
+    matches: &Matches,
+    paths: &[String],
+    free_args: String,
+) -> Result<OutputOptions, PrError> {
+    let form_feed_used = matches.opt_present(options::FORM_FEED_OPTION)
+        || matches.opt_present(options::FORM_FEED_OPTION_SMALL);
+
+    let is_merge_mode = matches.opt_present(options::MERGE_FILES_PRINT);
+
+    if is_merge_mode && matches.opt_present(options::COLUMN_OPTION) {
+        let err_msg = String::from("cannot specify number of columns when printing in parallel");
+        return Err(PrError::EncounteredErrors(err_msg));
+    }
+
+    if is_merge_mode && matches.opt_present(options::ACROSS_OPTION) {
+        let err_msg = String::from("cannot specify both printing across and printing in parallel");
+        return Err(PrError::EncounteredErrors(err_msg));
+    }
+
+    let merge_files_print = if matches.opt_present(options::MERGE_FILES_PRINT) {
+        Some(paths.len())
+    } else {
+        None
+    };
+
+    let header = matches.opt_str(options::STRING_HEADER_OPTION).unwrap_or(
+        if is_merge_mode || paths[0] == FILE_STDIN {
+            String::new()
+        } else {
+            paths[0].to_string()
+        },
+    );
+
+    let default_first_number = NumberingMode::default().first_number;
+    let first_number = parse_usize(matches, options::FIRST_LINE_NUMBER_OPTION)
+        .unwrap_or(Ok(default_first_number))?;
+
+    let number = matches
+        .opt_str(options::NUMBERING_MODE_OPTION)
+        .map(|i| {
+            let parse_result = i.parse::<usize>();
+
+            let separator = if parse_result.is_err() {
+                i[0..1].to_string()
+            } else {
+                NumberingMode::default().separator
+            };
+
+            let width = match parse_result {
+                Ok(res) => res,
+                Err(_) => i[1..]
+                    .parse::<usize>()
+                    .unwrap_or(NumberingMode::default().width),
+            };
+
+            NumberingMode {
+                width,
+                separator,
+                first_number,
+            }
+        })
+        .or_else(|| {
+            if matches.opt_present(options::NUMBERING_MODE_OPTION) {
+                Some(NumberingMode::default())
+            } else {
+                None
+            }
+        });
+
+    let double_space = matches.opt_present(options::DOUBLE_SPACE_OPTION);
+
+    let content_line_separator = if double_space {
+        "\n".repeat(2)
+    } else {
+        "\n".to_string()
+    };
+
+    let line_separator = "\n".to_string();
+
+    let last_modified_time = if is_merge_mode || paths[0].eq(FILE_STDIN) {
+        let date_time = Local::now();
+        date_time.format("%b %d %H:%M %Y").to_string()
+    } else {
+        file_last_modified_time(paths.get(0).unwrap())
+    };
+
+    // +page option is less priority than --pages
+    let page_plus_re = Regex::new(r"\s*\+(\d+:*\d*)\s*").unwrap();
+    let start_page_in_plus_option = match page_plus_re.captures(&free_args).map(|i| {
+        let unparsed_num = i.get(1).unwrap().as_str().trim();
+        let x: Vec<_> = unparsed_num.split(':').collect();
+        x[0].to_string().parse::<usize>().map_err(|_e| {
+            PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num))
+        })
+    }) {
+        Some(res) => res?,
+        None => 1,
+    };
+
+    let end_page_in_plus_option = match page_plus_re
+        .captures(&free_args)
+        .map(|i| i.get(1).unwrap().as_str().trim())
+        .filter(|i| i.contains(':'))
+        .map(|unparsed_num| {
+            let x: Vec<_> = unparsed_num.split(':').collect();
+            x[1].to_string().parse::<usize>().map_err(|_e| {
+                PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num))
+            })
+        }) {
+        Some(res) => Some(res?),
+        None => None,
+    };
+
+    let invalid_pages_map = |i: String| {
+        let unparsed_value = matches.opt_str(options::PAGE_RANGE_OPTION).unwrap();
+        i.parse::<usize>().map_err(|_e| {
+            PrError::EncounteredErrors(format!("invalid --pages argument '{}'", unparsed_value))
+        })
+    };
+
+    let start_page = match matches
+        .opt_str(options::PAGE_RANGE_OPTION)
+        .map(|i| {
+            let x: Vec<_> = i.split(':').collect();
+            x[0].to_string()
+        })
+        .map(invalid_pages_map)
+    {
+        Some(res) => res?,
+        None => start_page_in_plus_option,
+    };
+
+    let end_page = match matches
+        .opt_str(options::PAGE_RANGE_OPTION)
+        .filter(|i| i.contains(':'))
+        .map(|i| {
+            let x: Vec<_> = i.split(':').collect();
+            x[1].to_string()
+        })
+        .map(invalid_pages_map)
+    {
+        Some(res) => Some(res?),
+        None => end_page_in_plus_option,
+    };
+
+    if let Some(end_page) = end_page {
+        if start_page > end_page {
+            return Err(PrError::EncounteredErrors(format!(
+                "invalid --pages argument '{}:{}'",
+                start_page, end_page
+            )));
+        }
+    }
+
+    let default_lines_per_page = if form_feed_used {
+        LINES_PER_PAGE_FOR_FORM_FEED
+    } else {
+        LINES_PER_PAGE
+    };
+
+    let page_length =
+        parse_usize(matches, options::PAGE_LENGTH_OPTION).unwrap_or(Ok(default_lines_per_page))?;
+
+    let page_length_le_ht = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE);
+
+    let display_header_and_trailer =
+        !(page_length_le_ht) && !matches.opt_present(options::NO_HEADER_TRAILER_OPTION);
+
+    let content_lines_per_page = if page_length_le_ht {
+        page_length
+    } else {
+        page_length - (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE)
+    };
+
+    let page_separator_char = if matches.opt_present(options::FORM_FEED_OPTION) {
+        let bytes = vec![FF];
+        String::from_utf8(bytes).unwrap()
+    } else {
+        "\n".to_string()
+    };
+
+    let across_mode = matches.opt_present(options::ACROSS_OPTION);
+
+    let column_separator = match matches.opt_str(options::COLUMN_STRING_SEPARATOR_OPTION) {
+        Some(x) => Some(x),
+        None => matches.opt_str(options::COLUMN_CHAR_SEPARATOR_OPTION),
+    }
+    .unwrap_or_else(|| DEFAULT_COLUMN_SEPARATOR.to_string());
+
+    let default_column_width = if matches.opt_present(options::COLUMN_WIDTH_OPTION)
+        && matches.opt_present(options::COLUMN_CHAR_SEPARATOR_OPTION)
+    {
+        DEFAULT_COLUMN_WIDTH_WITH_S_OPTION
+    } else {
+        DEFAULT_COLUMN_WIDTH
+    };
+
+    let column_width =
+        parse_usize(matches, options::COLUMN_WIDTH_OPTION).unwrap_or(Ok(default_column_width))?;
+
+    let page_width = if matches.opt_present(options::JOIN_LINES_OPTION) {
+        None
+    } else {
+        match parse_usize(matches, options::PAGE_WIDTH_OPTION) {
+            Some(res) => Some(res?),
+            None => None,
+        }
+    };
+
+    let re_col = Regex::new(r"\s*-(\d+)\s*").unwrap();
+
+    let start_column_option = match re_col.captures(&free_args).map(|i| {
+        let unparsed_num = i.get(1).unwrap().as_str().trim();
+        unparsed_num.parse::<usize>().map_err(|_e| {
+            PrError::EncounteredErrors(format!("invalid {} argument '{}'", "-", unparsed_num))
+        })
+    }) {
+        Some(res) => Some(res?),
+        None => None,
+    };
+
+    // --column has more priority than -column
+
+    let column_option_value = match parse_usize(matches, options::COLUMN_OPTION) {
+        Some(res) => Some(res?),
+        None => start_column_option,
+    };
+
+    let column_mode_options = column_option_value.map(|columns| ColumnModeOptions {
+        columns,
+        width: column_width,
+        column_separator,
+        across_mode,
+    });
+
+    let offset_spaces =
+        " ".repeat(parse_usize(matches, options::OFFSET_SPACES_OPTION).unwrap_or(Ok(0))?);
+    let join_lines = matches.opt_present(options::JOIN_LINES_OPTION);
+
+    let col_sep_for_printing = column_mode_options
+        .as_ref()
+        .map(|i| i.column_separator.clone())
+        .unwrap_or_else(|| {
+            merge_files_print
+                .map(|_k| DEFAULT_COLUMN_SEPARATOR.to_string())
+                .unwrap_or_default()
+        });
+
+    let columns_to_print = merge_files_print
+        .unwrap_or_else(|| column_mode_options.as_ref().map(|i| i.columns).unwrap_or(1));
+
+    let line_width = if join_lines {
+        None
+    } else if columns_to_print > 1 {
+        Some(
+            column_mode_options
+                .as_ref()
+                .map(|i| i.width)
+                .unwrap_or(DEFAULT_COLUMN_WIDTH),
+        )
+    } else {
+        page_width
+    };
+
+    Ok(OutputOptions {
+        number,
+        header,
+        double_space,
+        line_separator,
+        content_line_separator,
+        last_modified_time,
+        start_page,
+        end_page,
+        display_header_and_trailer,
+        content_lines_per_page,
+        page_separator_char,
+        column_mode_options,
+        merge_files_print,
+        offset_spaces,
+        form_feed_used,
+        join_lines,
+        col_sep_for_printing,
+        line_width,
+    })
+}
+
+fn open(path: &str) -> Result<Box<dyn Read>, PrError> {
+    if path == FILE_STDIN {
+        let stdin = stdin();
+        return Ok(Box::new(stdin) as Box<dyn Read>);
+    }
+
+    metadata(path)
+        .map(|i| {
+            let path_string = path.to_string();
+            match i.file_type() {
+                #[cfg(unix)]
+                ft if ft.is_block_device() => Err(PrError::UnknownFiletype(path_string)),
+                #[cfg(unix)]
+                ft if ft.is_char_device() => Err(PrError::UnknownFiletype(path_string)),
+                #[cfg(unix)]
+                ft if ft.is_fifo() => Err(PrError::UnknownFiletype(path_string)),
+                #[cfg(unix)]
+                ft if ft.is_socket() => Err(PrError::IsSocket(path_string)),
+                ft if ft.is_dir() => Err(PrError::IsDirectory(path_string)),
+                ft if ft.is_file() || ft.is_symlink() => {
+                    Ok(Box::new(File::open(path).context(path)?) as Box<dyn Read>)
+                }
+                _ => Err(PrError::UnknownFiletype(path_string)),
+            }
+        })
+        .unwrap_or_else(|_| Err(PrError::NotExists(path.to_string())))
+}
+
+fn split_lines_if_form_feed(file_content: Result<String, IOError>) -> Vec<FileLine> {
+    file_content
+        .map(|content| {
+            let mut lines = Vec::new();
+            let mut f_occurred = 0;
+            let mut chunk = Vec::new();
+            for byte in content.as_bytes() {
+                if byte == &FF {
+                    f_occurred += 1;
+                } else {
+                    if f_occurred != 0 {
+                        // First time byte occurred in the scan
+                        lines.push(FileLine {
+                            line_content: Ok(String::from_utf8(chunk.clone()).unwrap()),
+                            form_feeds_after: f_occurred,
+                            ..FileLine::default()
+                        });
+                        chunk.clear();
+                    }
+                    chunk.push(*byte);
+                    f_occurred = 0;
+                }
+            }
+
+            lines.push(FileLine {
+                line_content: Ok(String::from_utf8(chunk).unwrap()),
+                form_feeds_after: f_occurred,
+                ..FileLine::default()
+            });
+
+            lines
+        })
+        .unwrap_or_else(|e| {
+            vec![FileLine {
+                line_content: Err(e),
+                ..FileLine::default()
+            }]
+        })
+}
+
+fn pr(path: &str, options: &OutputOptions) -> Result<i32, PrError> {
+    let lines = BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?).lines();
+
+    let pages = read_stream_and_create_pages(options, lines, 0);
+
+    for page_with_page_number in pages {
+        let page_number = page_with_page_number.0 + 1;
+        let page = page_with_page_number.1;
+        print_page(&page, options, page_number)?;
+    }
+
+    Ok(0)
+}
+
+fn read_stream_and_create_pages(
+    options: &OutputOptions,
+    lines: Lines<BufReader<Box<dyn Read>>>,
+    file_id: usize,
+) -> Box<dyn Iterator<Item = (usize, Vec<FileLine>)>> {
+    let start_page = options.start_page;
+    let start_line_number = get_start_line_number(options);
+    let last_page = options.end_page;
+    let lines_needed_per_page = lines_to_read_for_page(options);
+
+    Box::new(
+        lines
+            .map(split_lines_if_form_feed)
+            .flatten()
+            .enumerate()
+            .map(move |(i, line)| FileLine {
+                line_number: i + start_line_number,
+                file_id,
+                ..line
+            }) // Add line number and file_id
+            .batching(move |it| {
+                let mut first_page = Vec::new();
+                let mut page_with_lines = Vec::new();
+                for line in it {
+                    let form_feeds_after = line.form_feeds_after;
+                    first_page.push(line);
+
+                    if form_feeds_after > 1 {
+                        // insert empty pages
+                        page_with_lines.push(first_page);
+                        for _i in 1..form_feeds_after {
+                            page_with_lines.push(vec![]);
+                        }
+                        return Some(page_with_lines);
+                    }
+
+                    if first_page.len() == lines_needed_per_page || form_feeds_after == 1 {
+                        break;
+                    }
+                }
+
+                if first_page.is_empty() {
+                    return None;
+                }
+                page_with_lines.push(first_page);
+                Some(page_with_lines)
+            }) // Create set of pages as form feeds could lead to empty pages
+            .flatten() // Flatten to pages from page sets
+            .enumerate() // Assign page number
+            .skip_while(move |(x, _)| {
+                // Skip the not needed pages
+                let current_page = x + 1;
+                current_page < start_page
+            })
+            .take_while(move |(x, _)| {
+                // Take only the required pages
+                let current_page = x + 1;
+
+                current_page >= start_page
+                    && last_page.map_or(true, |last_page| current_page <= last_page)
+            }),
+    )
+}
+
+fn mpr(paths: &[String], options: &OutputOptions) -> Result<i32, PrError> {
+    let n_files = paths.len();
+
+    // Check if files exists
+    for path in paths {
+        open(path)?;
+    }
+
+    let file_line_groups = paths
+        .iter()
+        .enumerate()
+        .map(|(i, path)| {
+            let lines = BufReader::with_capacity(READ_BUFFER_SIZE, open(path).unwrap()).lines();
+
+            read_stream_and_create_pages(options, lines, i)
+                .map(move |(x, line)| {
+                    let file_line = line;
+                    let page_number = x + 1;
+                    file_line
+                        .into_iter()
+                        .map(|fl| FileLine {
+                            page_number,
+                            group_key: page_number * n_files + fl.file_id,
+                            ..fl
+                        })
+                        .collect::<Vec<_>>()
+                })
+                .flatten()
+        })
+        .kmerge_by(|a, b| {
+            if a.group_key == b.group_key {
+                a.line_number < b.line_number
+            } else {
+                a.group_key < b.group_key
+            }
+        })
+        .group_by(|file_line| file_line.group_key);
+
+    let start_page = options.start_page;
+    let mut lines = Vec::new();
+    let mut page_counter = start_page;
+
+    for (_key, file_line_group) in file_line_groups.into_iter() {
+        for file_line in file_line_group {
+            if let Err(e) = file_line.line_content {
+                return Err(e.into());
+            }
+            let new_page_number = file_line.page_number;
+            if page_counter != new_page_number {
+                print_page(&lines, options, page_counter)?;
+                lines = Vec::new();
+                page_counter = new_page_number;
+            }
+            lines.push(file_line);
+        }
+    }
+
+    print_page(&lines, options, page_counter)?;
+
+    Ok(0)
+}
+
+fn print_page(lines: &[FileLine], options: &OutputOptions, page: usize) -> Result<usize, IOError> {
+    let line_separator = options.line_separator.as_bytes();
+    let page_separator = options.page_separator_char.as_bytes();
+
+    let header = header_content(options, page);
+    let trailer_content = trailer_content(options);
+    let out = &mut stdout();
+
+    out.lock();
+    for x in header {
+        out.write_all(x.as_bytes())?;
+        out.write_all(line_separator)?;
+    }
+
+    let lines_written = write_columns(lines, options, out)?;
+
+    for (index, x) in trailer_content.iter().enumerate() {
+        out.write_all(x.as_bytes())?;
+        if index + 1 != trailer_content.len() {
+            out.write_all(line_separator)?;
+        }
+    }
+    out.write_all(page_separator)?;
+    out.flush()?;
+    Ok(lines_written)
+}
+
+fn write_columns(
+    lines: &[FileLine],
+    options: &OutputOptions,
+    out: &mut Stdout,
+) -> Result<usize, IOError> {
+    let line_separator = options.content_line_separator.as_bytes();
+
+    let content_lines_per_page = if options.double_space {
+        options.content_lines_per_page / 2
+    } else {
+        options.content_lines_per_page
+    };
+
+    let columns = options
+        .merge_files_print
+        .unwrap_or_else(|| get_columns(options));
+    let line_width = options.line_width;
+    let mut lines_printed = 0;
+    let feed_line_present = options.form_feed_used;
+    let mut not_found_break = false;
+
+    let across_mode = options
+        .column_mode_options
+        .as_ref()
+        .map(|i| i.across_mode)
+        .unwrap_or(false);
+
+    let mut filled_lines = Vec::new();
+    if options.merge_files_print.is_some() {
+        let mut offset = 0;
+        for col in 0..columns {
+            let mut inserted = 0;
+            for line in &lines[offset..] {
+                if line.file_id != col {
+                    break;
+                }
+                filled_lines.push(Some(line));
+                inserted += 1;
+            }
+            offset += inserted;
+
+            for _i in inserted..content_lines_per_page {
+                filled_lines.push(None);
+            }
+        }
+    }
+
+    let table: Vec<Vec<_>> = (0..content_lines_per_page)
+        .map(move |a| {
+            (0..columns)
+                .map(|i| {
+                    if across_mode {
+                        lines.get(a * columns + i)
+                    } else if options.merge_files_print.is_some() {
+                        *filled_lines
+                            .get(content_lines_per_page * i + a)
+                            .unwrap_or(&None)
+                    } else {
+                        lines.get(content_lines_per_page * i + a)
+                    }
+                })
+                .collect()
+        })
+        .collect();
+
+    let blank_line = FileLine::default();
+    for row in table {
+        let indexes = row.len();
+        for (i, cell) in row.iter().enumerate() {
+            if cell.is_none() && options.merge_files_print.is_some() {
+                out.write_all(
+                    get_line_for_printing(options, &blank_line, columns, i, &line_width, indexes)
+                        .as_bytes(),
+                )?;
+            } else if cell.is_none() {
+                not_found_break = true;
+                break;
+            } else if cell.is_some() {
+                let file_line = cell.unwrap();
+
+                out.write_all(
+                    get_line_for_printing(options, file_line, columns, i, &line_width, indexes)
+                        .as_bytes(),
+                )?;
+                lines_printed += 1;
+            }
+        }
+        if not_found_break && feed_line_present {
+            break;
+        } else {
+            out.write_all(line_separator)?;
+        }
+    }
+
+    Ok(lines_printed)
+}
+
+fn get_line_for_printing(
+    options: &OutputOptions,
+    file_line: &FileLine,
+    columns: usize,
+    index: usize,
+    line_width: &Option<usize>,
+    indexes: usize,
+) -> String {
+    let blank_line = String::new();
+    let formatted_line_number = get_formatted_line_number(options, file_line.line_number, index);
+
+    let mut complete_line = format!(
+        "{}{}",
+        formatted_line_number,
+        file_line.line_content.as_ref().unwrap()
+    );
+
+    let offset_spaces = &options.offset_spaces;
+
+    let tab_count = complete_line.chars().filter(|i| i == &TAB).count();
+
+    let display_length = complete_line.len() + (tab_count * 7);
+
+    let sep = if (index + 1) != indexes && !options.join_lines {
+        &options.col_sep_for_printing
+    } else {
+        &blank_line
+    };
+
+    format!(
+        "{}{}{}",
+        offset_spaces,
+        line_width
+            .map(|i| {
+                let min_width = (i - (columns - 1)) / columns;
+                if display_length < min_width {
+                    for _i in 0..(min_width - display_length) {
+                        complete_line.push(' ');
+                    }
+                }
+
+                complete_line.chars().take(min_width).collect()
+            })
+            .unwrap_or(complete_line),
+        sep
+    )
+}
+
+fn get_formatted_line_number(opts: &OutputOptions, line_number: usize, index: usize) -> String {
+    let should_show_line_number =
+        opts.number.is_some() && (opts.merge_files_print.is_none() || index == 0);
+    if should_show_line_number && line_number != 0 {
+        let line_str = line_number.to_string();
+        let num_opt = opts.number.as_ref().unwrap();
+        let width = num_opt.width;
+        let separator = &num_opt.separator;
+        if line_str.len() >= width {
+            format!(
+                "{:>width$}{}",
+                &line_str[line_str.len() - width..],
+                separator,
+                width = width
+            )
+        } else {
+            format!("{:>width$}{}", line_str, separator, width = width)
+        }
+    } else {
+        String::new()
+    }
+}
+
+/// Returns a five line header content if displaying header is not disabled by
+/// using `NO_HEADER_TRAILER_OPTION` option.
+fn header_content(options: &OutputOptions, page: usize) -> Vec<String> {
+    if options.display_header_and_trailer {
+        let first_line = format!(
+            "{} {} Page {}",
+            options.last_modified_time, options.header, page
+        );
+        vec![
+            String::new(),
+            String::new(),
+            first_line,
+            String::new(),
+            String::new(),
+        ]
+    } else {
+        Vec::new()
+    }
+}
+
+fn file_last_modified_time(path: &str) -> String {
+    metadata(path)
+        .map(|i| {
+            i.modified()
+                .map(|x| {
+                    let date_time: DateTime<Local> = x.into();
+                    date_time.format("%b %d %H:%M %Y").to_string()
+                })
+                .unwrap_or_default()
+        })
+        .unwrap_or_default()
+}
+
+/// Returns five empty lines as trailer content if displaying trailer
+/// is not disabled by using `NO_HEADER_TRAILER_OPTION`option.
+fn trailer_content(options: &OutputOptions) -> Vec<String> {
+    if options.display_header_and_trailer && !options.form_feed_used {
+        vec![
+            String::new(),
+            String::new(),
+            String::new(),
+            String::new(),
+            String::new(),
+        ]
+    } else {
+        Vec::new()
+    }
+}
+
+/// Returns starting line number for the file to be printed.
+/// If -N is specified the first line number changes otherwise
+/// default is 1.
+fn get_start_line_number(opts: &OutputOptions) -> usize {
+    opts.number.as_ref().map(|i| i.first_number).unwrap_or(1)
+}
+
+/// Returns number of lines to read from input for constructing one page of pr output.
+/// If double space -d is used lines are halved.
+/// If columns --columns is used the lines are multiplied by the value.
+fn lines_to_read_for_page(opts: &OutputOptions) -> usize {
+    let content_lines_per_page = opts.content_lines_per_page;
+    let columns = get_columns(opts);
+    if opts.double_space {
+        (content_lines_per_page / 2) * columns
+    } else {
+        content_lines_per_page * columns
+    }
+}
+
+/// Returns number of columns to output
+fn get_columns(opts: &OutputOptions) -> usize {
+    opts.column_mode_options
+        .as_ref()
+        .map(|i| i.columns)
+        .unwrap_or(1)
+}
+
+
\ No newline at end of file diff --git a/src/uu_printenv/printenv.rs.html b/src/uu_printenv/printenv.rs.html new file mode 100644 index 000000000..6793a4300 --- /dev/null +++ b/src/uu_printenv/printenv.rs.html @@ -0,0 +1,145 @@ +printenv.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+/* last synced with: printenv (GNU coreutils) 8.13 */
+
+use clap::{crate_version, App, Arg};
+use std::env;
+
+static ABOUT: &str = "Display the values of the specified environment VARIABLE(s), or (with no VARIABLE) display name and value pairs for them all.";
+
+static OPT_NULL: &str = "null";
+
+static ARG_VARIABLES: &str = "variables";
+
+fn usage() -> String {
+    format!("{0} [VARIABLE]... [OPTION]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let variables: Vec<String> = matches
+        .values_of(ARG_VARIABLES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let separator = if matches.is_present(OPT_NULL) {
+        "\x00"
+    } else {
+        "\n"
+    };
+
+    if variables.is_empty() {
+        for (env_var, value) in env::vars() {
+            print!("{}={}{}", env_var, value, separator);
+        }
+        return 0;
+    }
+
+    for env_var in variables {
+        if let Ok(var) = env::var(env_var) {
+            print!("{}{}", var, separator);
+        }
+    }
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_NULL)
+                .short("0")
+                .long(OPT_NULL)
+                .help("end each output line with 0 byte rather than newline"),
+        )
+        .arg(
+            Arg::with_name(ARG_VARIABLES)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/cli.rs.html b/src/uu_printf/cli.rs.html new file mode 100644 index 000000000..c098de22a --- /dev/null +++ b/src/uu_printf/cli.rs.html @@ -0,0 +1,69 @@ +cli.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+
+//! stdio convenience fns
+
+// spell-checker:ignore (ToDO) bslice
+
+use std::env;
+use std::io::{stderr, stdout, Write};
+
+pub const EXIT_OK: i32 = 0;
+pub const EXIT_ERR: i32 = 1;
+
+pub fn err_msg(msg: &str) {
+    let exe_path = match env::current_exe() {
+        Ok(p) => p.to_string_lossy().into_owned(),
+        _ => String::from(""),
+    };
+    writeln!(&mut stderr(), "{}: {}", exe_path, msg).unwrap();
+}
+
+// by default stdout only flushes
+// to console when a newline is passed.
+pub fn flush_char(c: char) {
+    print!("{}", c);
+    let _ = stdout().flush();
+}
+pub fn flush_str(s: &str) {
+    print!("{}", s);
+    let _ = stdout().flush();
+}
+pub fn flush_bytes(bslice: &[u8]) {
+    let _ = stdout().write(bslice);
+    let _ = stdout().flush();
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/memo.rs.html b/src/uu_printf/memo.rs.html new file mode 100644 index 000000000..0c96d2375 --- /dev/null +++ b/src/uu_printf/memo.rs.html @@ -0,0 +1,173 @@ +memo.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+
+//! Memo runner of printf
+//! Takes a format string and arguments
+//! 1. tokenize format string into tokens, consuming
+//! any subst. arguments along the way.
+//! 2. feeds remaining arguments into function
+//! that prints tokens.
+
+use itertools::put_back_n;
+use std::iter::Peekable;
+use std::slice::Iter;
+
+use crate::cli;
+use crate::tokenize::sub::Sub;
+use crate::tokenize::token::{Token, Tokenizer};
+use crate::tokenize::unescaped_text::UnescapedText;
+
+pub struct Memo {
+    tokens: Vec<Box<dyn Token>>,
+}
+
+fn warn_excess_args(first_arg: &str) {
+    cli::err_msg(&format!(
+        "warning: ignoring excess arguments, starting with '{}'",
+        first_arg
+    ));
+}
+
+impl Memo {
+    pub fn new(pf_string: &str, pf_args_it: &mut Peekable<Iter<String>>) -> Memo {
+        let mut pm = Memo { tokens: Vec::new() };
+        let mut tmp_token: Option<Box<dyn Token>>;
+        let mut it = put_back_n(pf_string.chars());
+        let mut has_sub = false;
+        loop {
+            tmp_token = UnescapedText::from_it(&mut it, pf_args_it);
+            if let Some(x) = tmp_token {
+                pm.tokens.push(x);
+            }
+            tmp_token = Sub::from_it(&mut it, pf_args_it);
+            if let Some(x) = tmp_token {
+                if !has_sub {
+                    has_sub = true;
+                }
+                pm.tokens.push(x);
+            }
+            if let Some(x) = it.next() {
+                it.put_back(x);
+            } else {
+                break;
+            }
+        }
+        if !has_sub {
+            let mut drain = false;
+            if let Some(first_arg) = pf_args_it.peek() {
+                warn_excess_args(first_arg);
+                drain = true;
+            }
+            if drain {
+                loop {
+                    // drain remaining args;
+                    if pf_args_it.next().is_none() {
+                        break;
+                    }
+                }
+            }
+        }
+        pm
+    }
+    pub fn apply(&self, pf_args_it: &mut Peekable<Iter<String>>) {
+        for tkn in self.tokens.iter() {
+            tkn.print(pf_args_it);
+        }
+    }
+    pub fn run_all(pf_string: &str, pf_args: &[String]) {
+        let mut arg_it = pf_args.iter().peekable();
+        let pm = Memo::new(pf_string, &mut arg_it);
+        loop {
+            if arg_it.peek().is_none() {
+                break;
+            }
+            pm.apply(&mut arg_it);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/printf.rs.html b/src/uu_printf/printf.rs.html new file mode 100644 index 000000000..133845d06 --- /dev/null +++ b/src/uu_printf/printf.rs.html @@ -0,0 +1,617 @@ +printf.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+
+#![allow(dead_code)]
+// spell-checker:ignore (change!) each's
+// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr
+
+use clap::{crate_version, App, Arg};
+use uucore::InvalidEncodingHandling;
+
+mod cli;
+mod memo;
+mod tokenize;
+
+const VERSION: &str = "version";
+const HELP: &str = "help";
+static LONGHELP_LEAD: &str = "printf
+
+ USAGE: printf FORMATSTRING [ARGUMENT]...
+
+ basic anonymous string templating:
+
+ prints format string at least once, repeating as long as there are remaining arguments
+ output prints escaped literals in the format string as character literals
+ output replaces anonymous fields with the next unused argument, formatted according to the field.
+
+Options:
+    --help              display this help and exit
+    --version           output version information and exit
+
+";
+static LONGHELP_BODY: &str = "
+  Prints the , replacing escaped character sequences with character literals
+    and substitution field sequences with passed arguments
+
+ literally, with the exception of the below
+    escaped character sequences, and the substitution sequences described further down.
+
+  ESCAPE SEQUENCES
+
+  The following escape sequences, organized here in alphabetical order,
+  will print the corresponding character literal:
+
+  \"   double quote
+
+  \\\\    backslash
+
+  \\a  alert (BEL)
+
+  \\b  backspace
+
+  \\c  End-of-Input
+
+  \\e  escape
+
+  \\f  form feed
+
+  \\n  new line
+
+  \\r  carriage return
+
+  \\t  horizontal tab
+
+  \\v  vertical tab
+
+  \\NNN byte with value expressed in octal value NNN (1 to 3 digits)
+        values greater than 256 will be treated
+
+  \\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)
+
+  \\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)
+
+  \\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)
+
+  %% a single %
+
+  SUBSTITUTIONS
+
+  SUBSTITUTION QUICK REFERENCE
+
+  Fields
+
+  %s - string
+  %b - string parsed for literals
+    second parameter is max length
+
+  %c - char
+    no second parameter
+
+  %i or %d - 64-bit integer
+  %u - 64 bit unsigned integer
+  %x or %X - 64-bit unsigned integer as hex
+  %o - 64-bit unsigned integer as octal
+    second parameter is min-width, integer
+     output below that width is padded with leading zeroes
+
+  %f or %F - decimal floating point value
+  %e or %E - scientific notation floating point value
+  %g or %G - shorter of specially interpreted decimal or SciNote floating point value.
+    second parameter is
+      -max places after decimal point for floating point output
+      -max number of significant digits for scientific notation output
+
+  parameterizing fields
+
+  examples:
+
+  printf '%4.3i' 7
+  has a first parameter of 4
+     and a second parameter of 3
+  will result in ' 007'
+
+  printf '%.1s' abcde
+  has no first parameter
+     and a second parameter of 1
+  will result in 'a'
+
+  printf '%4c' q
+  has a first parameter of 4
+     and no second parameter
+  will result in  '   q'
+
+  The first parameter of a field is the minimum width to pad the output to
+   if the output is less than this absolute value of this width,
+   it will be padded with leading spaces, or, if the argument is negative,
+   with trailing spaces. the default is zero.
+
+  The second parameter of a field is particular to the output field type.
+   defaults can be found in the full substitution help below
+
+  special prefixes to numeric arguments
+    0 (e.g. 010) - interpret argument as octal (integer output fields only)
+    0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
+    \' (e.g. \'a) - interpret argument as a character constant
+
+  HOW TO USE SUBSTITUTIONS
+
+  Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
+  particular way. E.g.
+
+      printf 'the letter %X comes before the letter %X' 10 11
+
+  will print
+
+     'the letter A comes before the letter B'
+
+  because the substitution field %X means
+  'take an integer argument and write it as a hexadecimal number'
+
+  Passing more arguments than are in the format string will cause the format string to be
+   repeated for the remaining substitutions
+
+     printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York
+
+  will print
+
+     'it is 22 F in Portland
+      it is 25 F in Boston
+      it is 27 F in Boston
+     '
+  If a format string is printed but there are less arguments remaining
+   than there are substitution fields, substitution fields without
+   an argument will default to empty strings, or for numeric fields
+   the value 0
+
+  AVAILABLE SUBSTITUTIONS
+
+  This program, like GNU coreutils printf,
+  interprets a modified subset of the POSIX C printf spec,
+  a quick reference to substitutions is below.
+
+   STRING SUBSTITUTIONS
+    All string fields have a 'max width' parameter
+    %.3s means 'print no more than three characters of the original input'
+
+   %s - string
+
+   %b - escaped string - the string will be checked for any escaped literals from
+         the escaped literal list above, and translate them to literal characters.
+         e.g. \\n will be transformed into a newline character.
+
+        One special rule about %b mode is that octal literals are interpreted differently
+        In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
+        instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
+        still be interpreted and not throw a warning, you will have problems if you use this for a
+        literal whose code begins with zero, as it will be viewed as in \\0NNN form.)
+
+   CHAR SUBSTITUTIONS
+    The character field does not have a secondary parameter.
+
+   %c - a single character
+
+   INTEGER SUBSTITUTIONS
+    All integer fields have a 'pad with zero' parameter
+    %.4i means an integer which if it is less than 4 digits in length,
+    is padded with leading zeros until it is 4 digits in length.
+
+   %d or %i - 64-bit integer
+
+   %u - 64 bit unsigned integer
+
+   %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
+            %X instead of %x means to use uppercase letters for 'a' through 'f'
+
+   %o - 64 bit unsigned integer printed in octal (base 8)
+
+   FLOATING POINT SUBSTITUTIONS
+
+    All floating point fields have a 'max decimal places / max significant digits' parameter
+    %.10f means a decimal floating point with 7 decimal places past 0
+    %.10e means a scientific notation number with 10 significant digits
+    %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
+          of each's output.
+
+    Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
+    double first before being rendered to text. For both implementations do not expect meaningful
+    precision past the 18th decimal place. When using a number of decimal places that is 18 or
+    higher, you can expect variation in output between GNU coreutils printf and this printf at the
+    18th decimal place of +/- 1
+
+   %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
+        default. There is not past-double behavior parity with Coreutils printf, values are not
+        estimated or adjusted beyond input values.
+
+   %e or %E - floating point value presented in scientific notation
+            7 significant digits by default
+            %E means use to use uppercase E for the mantissa.
+
+   %g or %G - floating point value presented in the shorter of decimal and scientific notation
+            behaves differently from %f and %E, please see posix printf spec for full details,
+            some examples of different behavior:
+
+            Sci Note has 6 significant digits by default
+            Trailing zeroes are removed
+            Instead of being truncated, digit after last is rounded
+
+   Like other behavior in this utility, the design choices of floating point
+    behavior in this utility is selected to reproduce in exact
+    the behavior of GNU coreutils' printf from an inputs and outputs standpoint.
+
+  USING PARAMETERS
+   Most substitution fields can be parameterized using up to 2 numbers that can
+   be passed to the field, between the % sign and the field letter.
+
+   The 1st parameter always indicates the minimum width of output, it is useful for creating
+     columnar output. Any output that would be less than this minimum width is padded with
+     leading spaces
+   The 2nd parameter is proceeded by a dot.
+   You do not have to use parameters
+
+  SPECIAL FORMS OF INPUT
+   For numeric input, the following additional forms of input are accepted besides decimal:
+
+    Octal (only with integer): if the argument begins with a 0 the proceeding characters
+      will be interpreted as octal (base 8) for integer fields
+
+    Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
+      will be interpreted as hex (base 16) for any numeric fields
+      for float fields, hexadecimal input results in a precision
+      limit (in converting input past the decimal point) of 10^-15
+
+    Character Constant: if the argument begins with a single quote character, the first byte
+      of the next character will be interpreted as an 8-bit unsigned integer. If there are
+      additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
+      is set)
+
+WRITTEN BY :
+  Nathan E. Ross, et al. for the uutils project
+
+MORE INFO :
+  https://github.com/uutils/coreutils
+
+COPYRIGHT :
+  Copyright 2015 uutils project.
+  Licensed under the MIT License, please see LICENSE file for details
+
+";
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    if args.len() <= 1 {
+        println!(
+            "{0}: missing operand\nTry '{1} --help' for more information.",
+            uucore::util_name(),
+            uucore::execution_phrase()
+        );
+        return 1;
+    }
+    let formatstr = &args[1];
+
+    if formatstr == "--help" {
+        print!("{} {}", LONGHELP_LEAD, LONGHELP_BODY);
+    } else if formatstr == "--version" {
+        println!("{} {}", uucore::util_name(), crate_version!());
+    } else {
+        let printf_args = &args[2..];
+        memo::Memo::run_all(formatstr, printf_args);
+    }
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .arg(Arg::with_name(VERSION).long(VERSION))
+        .arg(Arg::with_name(HELP).long(HELP))
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/mod.rs.html b/src/uu_printf/tokenize/mod.rs.html new file mode 100644 index 000000000..61621bf95 --- /dev/null +++ b/src/uu_printf/tokenize/mod.rs.html @@ -0,0 +1,15 @@ +mod.rs - source + +
1
+2
+3
+4
+5
+
+#[allow(clippy::module_inception)]
+mod num_format;
+pub mod sub;
+pub mod token;
+pub mod unescaped_text;
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/format_field.rs.html b/src/uu_printf/tokenize/num_format/format_field.rs.html new file mode 100644 index 000000000..eeca6ecd5 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/format_field.rs.html @@ -0,0 +1,91 @@ +format_field.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+
+//! Primitives used by Sub Tokenizer
+//! and num_format modules
+#[derive(Clone)]
+pub enum FieldType {
+    Strf,
+    Floatf,
+    CninetyNineHexFloatf,
+    Scif,
+    Decf,
+    Intf,
+    Charf,
+}
+
+// #[allow(non_camel_case_types)]
+// pub enum FChar {
+// d,
+// e,
+// E,
+// i,
+// f,
+// F,
+// g,
+// G,
+// u,
+// x,
+// X,
+// o
+// }
+//
+
+// a Sub Tokens' fields are stored
+// as a single object so they can be more simply
+// passed by ref to num_format in a Sub method
+#[derive(Clone)]
+pub struct FormatField<'a> {
+    pub min_width: Option<isize>,
+    pub second_field: Option<u32>,
+    pub field_char: &'a char,
+    pub field_type: &'a FieldType,
+    pub orig: &'a String,
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatter.rs.html b/src/uu_printf/tokenize/num_format/formatter.rs.html new file mode 100644 index 000000000..89881afdf --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatter.rs.html @@ -0,0 +1,145 @@ +formatter.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+
+//! Primitives used by num_format and sub_modules.
+//! never dealt with above (e.g. Sub Tokenizer never uses these)
+
+use itertools::{put_back_n, PutBackN};
+use std::str::Chars;
+
+use super::format_field::FormatField;
+
+use crate::cli;
+
+// contains the rough ingredients to final
+// output for a number, organized together
+// to allow for easy generalization of output manipulation
+// (e.g. max number of digits after decimal)
+pub struct FormatPrimitive {
+    pub prefix: Option<String>,
+    pub pre_decimal: Option<String>,
+    pub post_decimal: Option<String>,
+    pub suffix: Option<String>,
+}
+
+impl Default for FormatPrimitive {
+    fn default() -> FormatPrimitive {
+        FormatPrimitive {
+            prefix: None,
+            pre_decimal: None,
+            post_decimal: None,
+            suffix: None,
+        }
+    }
+}
+
+#[derive(Clone, PartialEq)]
+pub enum Base {
+    Ten = 10,
+    Hex = 16,
+    Octal = 8,
+}
+
+// information from the beginning of a numeric argument
+// the precedes the beginning of a numeric value
+pub struct InitialPrefix {
+    pub radix_in: Base,
+    pub sign: i8,
+    pub offset: usize,
+}
+
+pub trait Formatter {
+    //  return a FormatPrimitive for
+    // particular field char(s), given the argument
+    // string and prefix information (sign, radix)
+    fn get_primitive(
+        &self,
+        field: &FormatField,
+        in_prefix: &InitialPrefix,
+        str_in: &str,
+    ) -> Option<FormatPrimitive>;
+    // return a string from a FormatPrimitive,
+    // given information about the field
+    fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String;
+}
+pub fn get_it_at(offset: usize, str_in: &str) -> PutBackN<Chars> {
+    put_back_n(str_in[offset..].chars())
+}
+
+// TODO: put this somewhere better
+pub fn warn_incomplete_conv(pf_arg: &str) {
+    // important: keep println here not print
+    cli::err_msg(&format!("{}: value not completely converted", pf_arg))
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/base_conv/mod.rs.html b/src/uu_printf/tokenize/num_format/formatters/base_conv/mod.rs.html new file mode 100644 index 000000000..33e078bb2 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/base_conv/mod.rs.html @@ -0,0 +1,537 @@ +mod.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+
+// spell-checker:ignore (ToDO) arrnum arr_num mult basenum bufferval refd vals arrfloat conv intermed addl
+
+pub fn arrnum_int_mult(arr_num: &[u8], basenum: u8, base_ten_int_fact: u8) -> Vec<u8> {
+    let mut carry: u16 = 0;
+    let mut rem: u16;
+    let mut new_amount: u16;
+    let fact: u16 = u16::from(base_ten_int_fact);
+    let base: u16 = u16::from(basenum);
+
+    let mut ret_rev: Vec<u8> = Vec::new();
+    let mut it = arr_num.iter().rev();
+    loop {
+        let i = it.next();
+        match i {
+            Some(u) => {
+                new_amount = (u16::from(*u) * fact) + carry;
+                rem = new_amount % base;
+                carry = (new_amount - rem) / base;
+                ret_rev.push(rem as u8)
+            }
+            None => {
+                while carry != 0 {
+                    rem = carry % base;
+                    carry = (carry - rem) / base;
+                    ret_rev.push(rem as u8);
+                }
+                break;
+            }
+        }
+    }
+    let ret: Vec<u8> = ret_rev.into_iter().rev().collect();
+    ret
+}
+
+pub struct Remainder<'a> {
+    pub position: usize,
+    pub replace: Vec<u8>,
+    pub arr_num: &'a Vec<u8>,
+}
+
+pub struct DivOut<'a> {
+    pub quotient: u8,
+    pub remainder: Remainder<'a>,
+}
+
+pub fn arrnum_int_div_step(
+    rem_in: Remainder,
+    radix_in: u8,
+    base_ten_int_divisor: u8,
+    after_decimal: bool,
+) -> DivOut {
+    let mut rem_out = Remainder {
+        position: rem_in.position,
+        replace: Vec::new(),
+        arr_num: rem_in.arr_num,
+    };
+
+    let mut bufferval: u16 = 0;
+    let base: u16 = u16::from(radix_in);
+    let divisor: u16 = u16::from(base_ten_int_divisor);
+    let mut traversed = 0;
+
+    let mut quotient = 0;
+    let refd_vals = &rem_in.arr_num[rem_in.position + rem_in.replace.len()..];
+    let mut it_replace = rem_in.replace.iter();
+    let mut it_f = refd_vals.iter();
+    loop {
+        let u = match it_replace.next() {
+            Some(u_rep) => u16::from(*u_rep),
+            None => match it_f.next() {
+                Some(u_orig) => u16::from(*u_orig),
+                None => {
+                    if !after_decimal {
+                        break;
+                    }
+                    0
+                }
+            },
+        };
+        traversed += 1;
+        bufferval += u;
+        if bufferval > divisor {
+            while bufferval >= divisor {
+                quotient += 1;
+                bufferval -= divisor;
+            }
+            rem_out.replace = if bufferval == 0 {
+                Vec::new()
+            } else {
+                let remainder_as_arrnum = unsigned_to_arrnum(bufferval);
+                base_conv_vec(&remainder_as_arrnum, 10, radix_in)
+            };
+            rem_out.position += 1 + (traversed - rem_out.replace.len());
+            break;
+        } else {
+            bufferval *= base;
+        }
+    }
+    DivOut {
+        quotient,
+        remainder: rem_out,
+    }
+}
+pub fn arrnum_int_add(arrnum: &[u8], basenum: u8, base_ten_int_term: u8) -> Vec<u8> {
+    let mut carry: u16 = u16::from(base_ten_int_term);
+    let mut rem: u16;
+    let mut new_amount: u16;
+    let base: u16 = u16::from(basenum);
+
+    let mut ret_rev: Vec<u8> = Vec::new();
+    let mut it = arrnum.iter().rev();
+    loop {
+        let i = it.next();
+        match i {
+            Some(u) => {
+                new_amount = u16::from(*u) + carry;
+                rem = new_amount % base;
+                carry = (new_amount - rem) / base;
+                ret_rev.push(rem as u8)
+            }
+            None => {
+                while carry != 0 {
+                    rem = carry % base;
+                    carry = (carry - rem) / base;
+                    ret_rev.push(rem as u8);
+                }
+                break;
+            }
+        }
+    }
+    let ret: Vec<u8> = ret_rev.into_iter().rev().collect();
+    ret
+}
+
+pub fn base_conv_vec(src: &[u8], radix_src: u8, radix_dest: u8) -> Vec<u8> {
+    let mut result = vec![0];
+    for i in src {
+        result = arrnum_int_mult(&result, radix_dest, radix_src);
+        result = arrnum_int_add(&result, radix_dest, *i);
+    }
+    result
+}
+
+pub fn unsigned_to_arrnum(src: u16) -> Vec<u8> {
+    let mut result: Vec<u8> = Vec::new();
+    let mut src_tmp: u16 = src;
+    while src_tmp > 0 {
+        result.push((src_tmp % 10) as u8);
+        src_tmp /= 10;
+    }
+    result.reverse();
+    result
+}
+
+// temporary needs-improvement-function
+pub fn base_conv_float(src: &[u8], radix_src: u8, _radix_dest: u8) -> f64 {
+    // it would require a lot of addl code
+    // to implement this for arbitrary string input.
+    // until then, the below operates as an outline
+    // of how it would work.
+    let mut factor: f64 = 1_f64;
+    let radix_src_float: f64 = f64::from(radix_src);
+    let mut r: f64 = 0_f64;
+    for (i, u) in src.iter().enumerate() {
+        if i > 15 {
+            break;
+        }
+        factor /= radix_src_float;
+        r += factor * f64::from(*u)
+    }
+    r
+}
+
+pub fn str_to_arrnum(src: &str, radix_def_src: &dyn RadixDef) -> Vec<u8> {
+    let mut intermed_in: Vec<u8> = Vec::new();
+    for c in src.chars() {
+        #[allow(clippy::single_match)]
+        match radix_def_src.from_char(c) {
+            Some(u) => {
+                intermed_in.push(u);
+            }
+            None => {} //todo err msg on incorrect
+        }
+    }
+    intermed_in
+}
+
+pub fn arrnum_to_str(src: &[u8], radix_def_dest: &dyn RadixDef) -> String {
+    let mut str_out = String::new();
+    for u in src.iter() {
+        #[allow(clippy::single_match)]
+        match radix_def_dest.from_u8(*u) {
+            Some(c) => {
+                str_out.push(c);
+            }
+            None => {} //todo
+        }
+    }
+    str_out
+}
+
+pub fn base_conv_str(
+    src: &str,
+    radix_def_src: &dyn RadixDef,
+    radix_def_dest: &dyn RadixDef,
+) -> String {
+    let intermed_in: Vec<u8> = str_to_arrnum(src, radix_def_src);
+    let intermed_out = base_conv_vec(
+        &intermed_in,
+        radix_def_src.get_max(),
+        radix_def_dest.get_max(),
+    );
+    arrnum_to_str(&intermed_out, radix_def_dest)
+}
+
+pub trait RadixDef {
+    fn get_max(&self) -> u8;
+    fn from_char(&self, x: char) -> Option<u8>;
+    fn from_u8(&self, x: u8) -> Option<char>;
+}
+pub struct RadixTen;
+
+const ZERO_ASC: u8 = b'0';
+const UPPER_A_ASC: u8 = b'A';
+const LOWER_A_ASC: u8 = b'a';
+
+impl RadixDef for RadixTen {
+    fn get_max(&self) -> u8 {
+        10
+    }
+    fn from_char(&self, c: char) -> Option<u8> {
+        match c {
+            '0'..='9' => Some(c as u8 - ZERO_ASC),
+            _ => None,
+        }
+    }
+    fn from_u8(&self, u: u8) -> Option<char> {
+        match u {
+            0..=9 => Some((ZERO_ASC + u) as char),
+            _ => None,
+        }
+    }
+}
+pub struct RadixHex;
+impl RadixDef for RadixHex {
+    fn get_max(&self) -> u8 {
+        16
+    }
+    fn from_char(&self, c: char) -> Option<u8> {
+        match c {
+            '0'..='9' => Some(c as u8 - ZERO_ASC),
+            'A'..='F' => Some(c as u8 + 10 - UPPER_A_ASC),
+            'a'..='f' => Some(c as u8 + 10 - LOWER_A_ASC),
+            _ => None,
+        }
+    }
+    fn from_u8(&self, u: u8) -> Option<char> {
+        match u {
+            0..=9 => Some((ZERO_ASC + u) as char),
+            10..=15 => Some((UPPER_A_ASC + (u - 10)) as char),
+            _ => None,
+        }
+    }
+}
+
+mod tests;
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/base_conv/tests.rs.html b/src/uu_printf/tokenize/num_format/formatters/base_conv/tests.rs.html new file mode 100644 index 000000000..68043ef46 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/base_conv/tests.rs.html @@ -0,0 +1,117 @@ +tests.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+
+// spell-checker:ignore (ToDO) arrnum mult
+
+#[cfg(test)]
+use super::*;
+
+#[test]
+fn test_arrnum_int_mult() {
+    // (in base 10) 12 * 4 = 48
+    let factor: Vec<u8> = vec![1, 2];
+    let base_num = 10;
+    let base_ten_int_fact: u8 = 4;
+    let should_output: Vec<u8> = vec![4, 8];
+
+    let product = arrnum_int_mult(&factor, base_num, base_ten_int_fact);
+    assert!(product == should_output);
+}
+
+#[test]
+fn test_arrnum_int_non_base_10() {
+    // (in base 3)
+    // 5 * 4 = 20
+    let factor: Vec<u8> = vec![1, 2];
+    let base_num = 3;
+    let base_ten_int_fact: u8 = 4;
+    let should_output: Vec<u8> = vec![2, 0, 2];
+
+    let product = arrnum_int_mult(&factor, base_num, base_ten_int_fact);
+    assert!(product == should_output);
+}
+
+#[test]
+fn test_arrnum_int_div_short_circuit() {
+    // (
+    let arrnum: Vec<u8> = vec![5, 5, 5, 5, 0];
+    let base_num = 10;
+    let base_ten_int_divisor: u8 = 41;
+    let remainder_passed_in = Remainder {
+        position: 1,
+        replace: vec![1, 3],
+        arr_num: &arrnum,
+    };
+
+    // the "replace" should mean the number being divided
+    // is 1350, the first time you can get 41 to go into
+    // 1350, its at 135, where you can get a quotient of
+    // 3 and a remainder of 12;
+
+    let quotient_should_be: u8 = 3;
+    let remainder_position_should_be: usize = 3;
+    let remainder_replace_should_be = vec![1, 2];
+
+    let result = arrnum_int_div_step(remainder_passed_in, base_num, base_ten_int_divisor, false);
+    assert!(quotient_should_be == result.quotient);
+    assert!(remainder_position_should_be == result.remainder.position);
+    assert!(remainder_replace_should_be == result.remainder.replace);
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/cninetyninehexfloatf.rs.html b/src/uu_printf/tokenize/num_format/formatters/cninetyninehexfloatf.rs.html new file mode 100644 index 000000000..ffad9f622 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/cninetyninehexfloatf.rs.html @@ -0,0 +1,229 @@ +cninetyninehexfloatf.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+// spell-checker:ignore (ToDO) arrnum
+
+//! formatter for %a %F C99 Hex-floating-point subs
+use super::super::format_field::FormatField;
+use super::super::formatter::{FormatPrimitive, Formatter, InitialPrefix};
+use super::base_conv;
+use super::base_conv::RadixDef;
+use super::float_common::{primitive_to_str_common, FloatAnalysis};
+
+pub struct CninetyNineHexFloatf {
+    as_num: f64,
+}
+impl CninetyNineHexFloatf {
+    pub fn new() -> CninetyNineHexFloatf {
+        CninetyNineHexFloatf { as_num: 0.0 }
+    }
+}
+
+impl Formatter for CninetyNineHexFloatf {
+    fn get_primitive(
+        &self,
+        field: &FormatField,
+        initial_prefix: &InitialPrefix,
+        str_in: &str,
+    ) -> Option<FormatPrimitive> {
+        let second_field = field.second_field.unwrap_or(6) + 1;
+        let analysis = FloatAnalysis::analyze(
+            str_in,
+            initial_prefix,
+            Some(second_field as usize),
+            None,
+            true,
+        );
+        let f = get_primitive_hex(
+            initial_prefix,
+            &str_in[initial_prefix.offset..],
+            &analysis,
+            second_field as usize,
+            *field.field_char == 'A',
+        );
+        Some(f)
+    }
+    fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
+        primitive_to_str_common(prim, &field)
+    }
+}
+
+// c99 hex has unique requirements of all floating point subs in pretty much every part of building a primitive, from prefix and suffix to need for base conversion (in all other cases if you don't have decimal you must have decimal, here it's the other way around)
+
+// on the todo list is to have a trait for get_primitive that is implemented by each float formatter and can override a default. when that happens we can take the parts of get_primitive_dec specific to dec and spin them out to their own functions that can be overridden.
+fn get_primitive_hex(
+    initial_prefix: &InitialPrefix,
+    _str_in: &str,
+    _analysis: &FloatAnalysis,
+    _last_dec_place: usize,
+    capitalized: bool,
+) -> FormatPrimitive {
+    let prefix = Some(String::from(if initial_prefix.sign == -1 {
+        "-0x"
+    } else {
+        "0x"
+    }));
+
+    // TODO actual conversion, make sure to get back mantissa.
+    // for hex to hex, it's really just a matter of moving the
+    // decimal point and calculating the mantissa by its initial
+    // position and its moves, with every position counting for
+    // the addition or subtraction of 4 (2**4, because 4 bits in a hex digit)
+    // to the exponent.
+    // decimal's going to be a little more complicated. correct simulation
+    // of glibc will require after-decimal division to a specified precision.
+    // the difficult part of this (arrnum_int_div_step) is already implemented.
+
+    // the hex float name may be a bit misleading in terms of how to go about the
+    // conversion. The best way to do it is to just convert the float number
+    // directly to base 2 and then at the end translate back to hex.
+    let mantissa = 0;
+    let suffix = Some({
+        let ind = if capitalized { "P" } else { "p" };
+        if mantissa >= 0 {
+            format!("{}+{}", ind, mantissa)
+        } else {
+            format!("{}{}", ind, mantissa)
+        }
+    });
+    FormatPrimitive {
+        prefix,
+        suffix,
+        ..Default::default()
+    }
+}
+
+fn to_hex(src: &str, before_decimal: bool) -> String {
+    let radix_ten = base_conv::RadixTen;
+    let radix_hex = base_conv::RadixHex;
+    if before_decimal {
+        base_conv::base_conv_str(src, &radix_ten, &radix_hex)
+    } else {
+        let as_arrnum_ten = base_conv::str_to_arrnum(src, &radix_ten);
+        let s = format!(
+            "{}",
+            base_conv::base_conv_float(&as_arrnum_ten, radix_ten.get_max(), radix_hex.get_max())
+        );
+        if s.len() > 2 {
+            String::from(&s[2..])
+        } else {
+            // zero
+            s
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/decf.rs.html b/src/uu_printf/tokenize/num_format/formatters/decf.rs.html new file mode 100644 index 000000000..1dc25ded2 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/decf.rs.html @@ -0,0 +1,167 @@ +decf.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+
+//! formatter for %g %G decimal subs
+use super::super::format_field::FormatField;
+use super::super::formatter::{FormatPrimitive, Formatter, InitialPrefix};
+use super::float_common::{get_primitive_dec, primitive_to_str_common, FloatAnalysis};
+
+fn get_len_fmt_primitive(fmt: &FormatPrimitive) -> usize {
+    let mut len = 0;
+    if let Some(ref s) = fmt.prefix {
+        len += s.len();
+    }
+    if let Some(ref s) = fmt.pre_decimal {
+        len += s.len();
+    }
+    if let Some(ref s) = fmt.post_decimal {
+        len += s.len();
+    }
+    if let Some(ref s) = fmt.suffix {
+        len += s.len();
+    }
+    len
+}
+
+pub struct Decf;
+
+impl Decf {
+    pub fn new() -> Decf {
+        Decf
+    }
+}
+impl Formatter for Decf {
+    fn get_primitive(
+        &self,
+        field: &FormatField,
+        initial_prefix: &InitialPrefix,
+        str_in: &str,
+    ) -> Option<FormatPrimitive> {
+        let second_field = field.second_field.unwrap_or(6) + 1;
+        // default to scif interpretation so as to not truncate input vals
+        // (that would be displayed in scif) based on relation to decimal place
+        let analysis = FloatAnalysis::analyze(
+            str_in,
+            initial_prefix,
+            Some(second_field as usize + 1),
+            None,
+            false,
+        );
+        let mut f_sci = get_primitive_dec(
+            initial_prefix,
+            &str_in[initial_prefix.offset..],
+            &analysis,
+            second_field as usize,
+            Some(*field.field_char == 'G'),
+        );
+        // strip trailing zeroes
+        if let Some(ref post_dec) = f_sci.post_decimal {
+            let trimmed = post_dec.trim_end_matches('0');
+            if trimmed.len() != post_dec.len() {
+                f_sci.post_decimal = Some(trimmed.to_owned());
+            }
+        }
+        let f_fl = get_primitive_dec(
+            initial_prefix,
+            &str_in[initial_prefix.offset..],
+            &analysis,
+            second_field as usize,
+            None,
+        );
+        Some(
+            if get_len_fmt_primitive(&f_fl) >= get_len_fmt_primitive(&f_sci) {
+                f_sci
+            } else {
+                f_fl
+            },
+        )
+    }
+    fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
+        primitive_to_str_common(prim, &field)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/float_common.rs.html b/src/uu_printf/tokenize/num_format/formatters/float_common.rs.html new file mode 100644 index 000000000..9d5b96bff --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/float_common.rs.html @@ -0,0 +1,705 @@ +float_common.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+// spell-checker:ignore (ToDO) arrnum
+
+use super::super::format_field::FormatField;
+use super::super::formatter::{
+    get_it_at, warn_incomplete_conv, Base, FormatPrimitive, InitialPrefix,
+};
+use super::base_conv;
+use super::base_conv::RadixDef;
+
+// if the memory, copy, and comparison cost of chars
+//  becomes an issue, we can always operate in vec<u8> here
+//  rather than just at de_hex
+
+pub struct FloatAnalysis {
+    pub len_important: usize,
+    // none means no decimal point.
+    pub decimal_pos: Option<usize>,
+    pub follow: Option<char>,
+}
+fn has_enough_digits(
+    hex_input: bool,
+    hex_output: bool,
+    string_position: usize,
+    starting_position: usize,
+    limit: usize,
+) -> bool {
+    // -1s are for rounding
+    if hex_output {
+        if hex_input {
+            (string_position - 1) - starting_position >= limit
+        } else {
+            false //undecidable without converting
+        }
+    } else if hex_input {
+        (((string_position - 1) - starting_position) * 9) / 8 >= limit
+    } else {
+        (string_position - 1) - starting_position >= limit
+    }
+}
+
+impl FloatAnalysis {
+    pub fn analyze(
+        str_in: &str,
+        initial_prefix: &InitialPrefix,
+        max_sd_opt: Option<usize>,
+        max_after_dec_opt: Option<usize>,
+        hex_output: bool,
+    ) -> FloatAnalysis {
+        // this fn assumes
+        // the input string
+        // has no leading spaces or 0s
+        let str_it = get_it_at(initial_prefix.offset, str_in);
+        let mut ret = FloatAnalysis {
+            len_important: 0,
+            decimal_pos: None,
+            follow: None,
+        };
+        let hex_input = match initial_prefix.radix_in {
+            Base::Hex => true,
+            Base::Ten => false,
+            Base::Octal => {
+                panic!("this should never happen: floats should never receive octal input");
+            }
+        };
+        let mut i = 0;
+        let mut pos_before_first_nonzero_after_decimal: Option<usize> = None;
+        for c in str_it {
+            match c {
+                e @ '0'..='9' | e @ 'A'..='F' | e @ 'a'..='f' => {
+                    if !hex_input {
+                        match e {
+                            '0'..='9' => {}
+                            _ => {
+                                warn_incomplete_conv(str_in);
+                                break;
+                            }
+                        }
+                    }
+                    if ret.decimal_pos.is_some()
+                        && pos_before_first_nonzero_after_decimal.is_none()
+                        && e != '0'
+                    {
+                        pos_before_first_nonzero_after_decimal = Some(i - 1);
+                    }
+                    if let Some(max_sd) = max_sd_opt {
+                        if i == max_sd {
+                            // follow is used in cases of %g
+                            // where the character right after the last
+                            // sd is considered is rounded affecting
+                            // the previous digit in 1/2 of instances
+                            ret.follow = Some(e);
+                        } else if ret.decimal_pos.is_some() && i > max_sd {
+                            break;
+                        }
+                    }
+                    if let Some(max_after_dec) = max_after_dec_opt {
+                        if let Some(p) = ret.decimal_pos {
+                            if has_enough_digits(hex_input, hex_output, i, p, max_after_dec) {
+                                break;
+                            }
+                        }
+                    } else if let Some(max_sd) = max_sd_opt {
+                        if let Some(p) = pos_before_first_nonzero_after_decimal {
+                            if has_enough_digits(hex_input, hex_output, i, p, max_sd) {
+                                break;
+                            }
+                        }
+                    }
+                }
+                '.' => {
+                    if ret.decimal_pos.is_none() {
+                        ret.decimal_pos = Some(i);
+                    } else {
+                        warn_incomplete_conv(str_in);
+                        break;
+                    }
+                }
+                _ => {
+                    warn_incomplete_conv(str_in);
+                    break;
+                }
+            };
+            i += 1;
+        }
+        ret.len_important = i;
+        ret
+    }
+}
+
+fn de_hex(src: &str, before_decimal: bool) -> String {
+    let radix_ten = base_conv::RadixTen;
+    let radix_hex = base_conv::RadixHex;
+    if before_decimal {
+        base_conv::base_conv_str(src, &radix_hex, &radix_ten)
+    } else {
+        let as_arrnum_hex = base_conv::str_to_arrnum(src, &radix_hex);
+        let s = format!(
+            "{}",
+            base_conv::base_conv_float(&as_arrnum_hex, radix_hex.get_max(), radix_ten.get_max())
+        );
+        if s.len() > 2 {
+            String::from(&s[2..])
+        } else {
+            // zero
+            s
+        }
+    }
+}
+
+// takes a string in,
+// truncates to a position,
+// bumps the last digit up one,
+// and if the digit was nine
+// propagate to the next, etc.
+fn _round_str_from(in_str: &str, position: usize) -> (String, bool) {
+    let mut it = in_str[0..position].chars();
+    let mut rev = String::new();
+    let mut i = position;
+    let mut finished_in_dec = false;
+    while let Some(c) = it.next_back() {
+        i -= 1;
+        match c {
+            '9' => {
+                rev.push('0');
+            }
+            e => {
+                rev.push(((e as u8) + 1) as char);
+                finished_in_dec = true;
+                break;
+            }
+        }
+    }
+    let mut fwd = String::from(&in_str[0..i]);
+    for ch in rev.chars().rev() {
+        fwd.push(ch);
+    }
+    (fwd, finished_in_dec)
+}
+
+fn round_terminal_digit(
+    before_dec: String,
+    after_dec: String,
+    position: usize,
+) -> (String, String) {
+    if position < after_dec.len() {
+        let digit_at_pos: char;
+        {
+            digit_at_pos = (&after_dec[position..=position]).chars().next().expect("");
+        }
+        if let '5'..='9' = digit_at_pos {
+            let (new_after_dec, finished_in_dec) = _round_str_from(&after_dec, position);
+            if finished_in_dec {
+                return (before_dec, new_after_dec);
+            } else {
+                let (new_before_dec, _) = _round_str_from(&before_dec, before_dec.len());
+                return (new_before_dec, new_after_dec);
+            }
+            // TODO
+        }
+    }
+    (before_dec, after_dec)
+}
+
+pub fn get_primitive_dec(
+    initial_prefix: &InitialPrefix,
+    str_in: &str,
+    analysis: &FloatAnalysis,
+    last_dec_place: usize,
+    sci_mode: Option<bool>,
+) -> FormatPrimitive {
+    let mut f: FormatPrimitive = Default::default();
+
+    // add negative sign section
+    if initial_prefix.sign == -1 {
+        f.prefix = Some(String::from("-"));
+    }
+
+    // assign the digits before and after the decimal points
+    // to separate slices. If no digits after decimal point,
+    // assign 0
+    let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
+        Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
+        None => (str_in, "0"),
+    };
+    if first_segment_raw.is_empty() {
+        first_segment_raw = "0";
+    }
+    // convert to string, de_hexifying if input is in hex   // spell-checker:disable-line
+    let (first_segment, second_segment) = match initial_prefix.radix_in {
+        Base::Hex => (
+            de_hex(first_segment_raw, true),
+            de_hex(second_segment_raw, false),
+        ),
+        _ => (
+            String::from(first_segment_raw),
+            String::from(second_segment_raw),
+        ),
+    };
+    let (pre_dec_unrounded, post_dec_unrounded, mantissa) = if sci_mode.is_some() {
+        if first_segment.len() > 1 {
+            let mut post_dec = String::from(&first_segment[1..]);
+            post_dec.push_str(&second_segment);
+            (
+                String::from(&first_segment[0..1]),
+                post_dec,
+                first_segment.len() as isize - 1,
+            )
+        } else {
+            match first_segment
+                .chars()
+                .next()
+                .expect("float_common: no chars in first segment.")
+            {
+                '0' => {
+                    let it = second_segment.chars().enumerate();
+                    let mut m: isize = 0;
+                    let mut pre = String::from("0");
+                    let mut post = String::from("0");
+                    for (i, c) in it {
+                        match c {
+                            '0' => {}
+                            _ => {
+                                m = -((i as isize) + 1);
+                                pre = String::from(&second_segment[i..=i]);
+                                post = String::from(&second_segment[i + 1..]);
+                                break;
+                            }
+                        }
+                    }
+                    (pre, post, m)
+                }
+                _ => (first_segment, second_segment, 0),
+            }
+        }
+    } else {
+        (first_segment, second_segment, 0)
+    };
+
+    let (pre_dec_draft, post_dec_draft) =
+        round_terminal_digit(pre_dec_unrounded, post_dec_unrounded, last_dec_place - 1);
+
+    f.pre_decimal = Some(pre_dec_draft);
+    f.post_decimal = Some(post_dec_draft);
+    if let Some(capitalized) = sci_mode {
+        let si_ind = if capitalized { 'E' } else { 'e' };
+        f.suffix = Some(if mantissa >= 0 {
+            format!("{}+{:02}", si_ind, mantissa)
+        } else {
+            // negative sign is considered in format!s
+            // leading zeroes
+            format!("{}{:03}", si_ind, mantissa)
+        });
+    }
+
+    f
+}
+
+pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
+    let mut final_str = String::new();
+    if let Some(ref prefix) = prim.prefix {
+        final_str.push_str(prefix);
+    }
+    match prim.pre_decimal {
+        Some(ref pre_decimal) => {
+            final_str.push_str(pre_decimal);
+        }
+        None => {
+            panic!(
+                "error, format primitives provided to int, will, incidentally under correct \
+                 behavior, always have a pre_dec value."
+            );
+        }
+    }
+    let decimal_places = field.second_field.unwrap_or(6);
+    match prim.post_decimal {
+        Some(ref post_decimal) => {
+            if !post_decimal.is_empty() && decimal_places > 0 {
+                final_str.push('.');
+                let len_avail = post_decimal.len() as u32;
+
+                if decimal_places >= len_avail {
+                    // println!("dec {}, len avail {}", decimal_places, len_avail);
+                    final_str.push_str(post_decimal);
+
+                    if *field.field_char != 'g' && *field.field_char != 'G' {
+                        let diff = decimal_places - len_avail;
+                        for _ in 0..diff {
+                            final_str.push('0');
+                        }
+                    }
+                } else {
+                    // println!("printing to only {}", decimal_places);
+                    final_str.push_str(&post_decimal[0..decimal_places as usize]);
+                }
+            }
+        }
+        None => {
+            panic!(
+                "error, format primitives provided to int, will, incidentally under correct \
+                 behavior, always have a pre_dec value."
+            );
+        }
+    }
+    if let Some(ref suffix) = prim.suffix {
+        final_str.push_str(suffix);
+    }
+
+    final_str
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/floatf.rs.html b/src/uu_printf/tokenize/num_format/formatters/floatf.rs.html new file mode 100644 index 000000000..008ec6f99 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/floatf.rs.html @@ -0,0 +1,89 @@ +floatf.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+// spell-checker:ignore (ToDO) arrnum
+
+//! formatter for %f %F common-notation floating-point subs
+use super::super::format_field::FormatField;
+use super::super::formatter::{FormatPrimitive, Formatter, InitialPrefix};
+use super::float_common::{get_primitive_dec, primitive_to_str_common, FloatAnalysis};
+
+pub struct Floatf;
+impl Floatf {
+    pub fn new() -> Floatf {
+        Floatf
+    }
+}
+impl Formatter for Floatf {
+    fn get_primitive(
+        &self,
+        field: &FormatField,
+        initial_prefix: &InitialPrefix,
+        str_in: &str,
+    ) -> Option<FormatPrimitive> {
+        let second_field = field.second_field.unwrap_or(6) + 1;
+        let analysis = FloatAnalysis::analyze(
+            str_in,
+            initial_prefix,
+            None,
+            Some(second_field as usize),
+            false,
+        );
+        let f = get_primitive_dec(
+            initial_prefix,
+            &str_in[initial_prefix.offset..],
+            &analysis,
+            second_field as usize,
+            None,
+        );
+        Some(f)
+    }
+    fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
+        primitive_to_str_common(prim, &field)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/intf.rs.html b/src/uu_printf/tokenize/num_format/formatters/intf.rs.html new file mode 100644 index 000000000..ea1718fee --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/intf.rs.html @@ -0,0 +1,565 @@ +intf.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+// spell-checker:ignore (ToDO) arrnum
+
+//! formatter for unsigned and signed int subs
+//! unsigned int: %X %x (hex u64) %o (octal u64) %u (base ten u64)
+//! signed int: %i %d (both base ten i64)
+use super::super::format_field::FormatField;
+use super::super::formatter::{
+    get_it_at, warn_incomplete_conv, Base, FormatPrimitive, Formatter, InitialPrefix,
+};
+use std::i64;
+use std::u64;
+
+pub struct Intf {
+    _a: u32,
+}
+
+// see the Intf::analyze() function below
+struct IntAnalysis {
+    check_past_max: bool,
+    past_max: bool,
+    is_zero: bool,
+    len_digits: u8,
+}
+
+impl Intf {
+    pub fn new() -> Intf {
+        Intf { _a: 0 }
+    }
+    // take a ref to argument string, and basic information
+    // about prefix (offset, radix, sign), and analyze string
+    // to gain the IntAnalysis information above
+    // check_past_max: true if the number *may* be above max,
+    //   but we don't know either way. One of several reasons
+    //   we may have to parse as int.
+    // past_max: true if the object is past max, false if not
+    //  in the future we should probably combine these into an
+    //  Option<bool>
+    // is_zero: true if number is zero, false otherwise
+    // len_digits: length of digits used to create the int
+    //   important, for example, if we run into a non-valid character
+    fn analyze(str_in: &str, signed_out: bool, initial_prefix: &InitialPrefix) -> IntAnalysis {
+        // the maximum number of digits we could conceivably
+        // have before the decimal point without exceeding the
+        // max
+        let mut str_it = get_it_at(initial_prefix.offset, str_in);
+        let max_sd_in = if signed_out {
+            match initial_prefix.radix_in {
+                Base::Ten => 19,
+                Base::Octal => 21,
+                Base::Hex => 16,
+            }
+        } else {
+            match initial_prefix.radix_in {
+                Base::Ten => 20,
+                Base::Octal => 22,
+                Base::Hex => 16,
+            }
+        };
+        let mut ret = IntAnalysis {
+            check_past_max: false,
+            past_max: false,
+            is_zero: false,
+            len_digits: 0,
+        };
+
+        // todo turn this to a while let now that we know
+        // no special behavior on EOI break
+        loop {
+            let c_opt = str_it.next();
+            if let Some(c) = c_opt {
+                match c {
+                    '0'..='9' | 'a'..='f' | 'A'..='F' => {
+                        if ret.len_digits == 0 && c == '0' {
+                            ret.is_zero = true;
+                        } else if ret.is_zero {
+                            ret.is_zero = false;
+                        }
+                        ret.len_digits += 1;
+                        if ret.len_digits == max_sd_in {
+                            if let Some(next_ch) = str_it.next() {
+                                match next_ch {
+                                    '0'..='9' => {
+                                        ret.past_max = true;
+                                    }
+                                    _ => {
+                                        // force conversion
+                                        // to check if its above max.
+                                        // todo: spin out convert
+                                        // into fn, call it here to try
+                                        // read val, on Ok()
+                                        // save val for reuse later
+                                        // that way on same-base in and out
+                                        // we don't needlessly convert int
+                                        // to str, we can just copy it over.
+                                        ret.check_past_max = true;
+                                        str_it.put_back(next_ch);
+                                    }
+                                }
+                                if ret.past_max {
+                                    break;
+                                }
+                            } else {
+                                ret.check_past_max = true;
+                            }
+                        }
+                    }
+                    _ => {
+                        warn_incomplete_conv(str_in);
+                        break;
+                    }
+                }
+            } else {
+                // breaks on EOL
+                break;
+            }
+        }
+        ret
+    }
+    // get a FormatPrimitive of the maximum value for the field char
+    //  and given sign
+    fn get_max(field_char: char, sign: i8) -> FormatPrimitive {
+        let mut fmt_primitive: FormatPrimitive = Default::default();
+        fmt_primitive.pre_decimal = Some(String::from(match field_char {
+            'd' | 'i' => match sign {
+                1 => "9223372036854775807",
+                _ => {
+                    fmt_primitive.prefix = Some(String::from("-"));
+                    "9223372036854775808"
+                }
+            },
+            'x' | 'X' => "ffffffffffffffff",
+            'o' => "1777777777777777777777",
+            /* 'u' | */ _ => "18446744073709551615",
+        }));
+        fmt_primitive
+    }
+    // conv_from_segment contract:
+    // 1. takes
+    // - a string that begins with a non-zero digit, and proceeds
+    //  with zero or more following digits until the end of the string
+    // - a radix to interpret those digits as
+    // - a char that communicates:
+    //     whether to interpret+output the string as an i64 or u64
+    //     what radix to write the parsed number as.
+    // 2. parses it as a rust integral type
+    // 3. outputs FormatPrimitive with:
+    // - if the string falls within bounds:
+    //   number parsed and written in the correct radix
+    // - if the string falls outside bounds:
+    //   for i64 output, the int minimum or int max (depending on sign)
+    //   for u64 output, the u64 max in the output radix
+    fn conv_from_segment(
+        segment: &str,
+        radix_in: Base,
+        field_char: char,
+        sign: i8,
+    ) -> FormatPrimitive {
+        match field_char {
+            'i' | 'd' => match i64::from_str_radix(segment, radix_in as u32) {
+                Ok(i) => {
+                    let mut fmt_prim: FormatPrimitive = Default::default();
+                    if sign == -1 {
+                        fmt_prim.prefix = Some(String::from("-"));
+                    }
+                    fmt_prim.pre_decimal = Some(format!("{}", i));
+                    fmt_prim
+                }
+                Err(_) => Intf::get_max(field_char, sign),
+            },
+            _ => match u64::from_str_radix(segment, radix_in as u32) {
+                Ok(u) => {
+                    let mut fmt_prim: FormatPrimitive = Default::default();
+                    let u_f = if sign == -1 { u64::MAX - (u - 1) } else { u };
+                    fmt_prim.pre_decimal = Some(match field_char {
+                        'X' => format!("{:X}", u_f),
+                        'x' => format!("{:x}", u_f),
+                        'o' => format!("{:o}", u_f),
+                        _ => format!("{}", u_f),
+                    });
+                    fmt_prim
+                }
+                Err(_) => Intf::get_max(field_char, sign),
+            },
+        }
+    }
+}
+impl Formatter for Intf {
+    fn get_primitive(
+        &self,
+        field: &FormatField,
+        initial_prefix: &InitialPrefix,
+        str_in: &str,
+    ) -> Option<FormatPrimitive> {
+        let begin = initial_prefix.offset;
+
+        // get information about the string. see Intf::Analyze
+        // def above.
+        let convert_hints = Intf::analyze(
+            str_in,
+            *field.field_char == 'i' || *field.field_char == 'd',
+            initial_prefix,
+        );
+        // We always will have a format primitive to return
+        Some(if convert_hints.len_digits == 0 || convert_hints.is_zero {
+            // if non-digit or end is reached before a non-zero digit
+            FormatPrimitive {
+                pre_decimal: Some(String::from("0")),
+                ..Default::default()
+            }
+        } else if !convert_hints.past_max {
+            // if the number is or may be below the bounds limit
+            let radix_out = match *field.field_char {
+                'd' | 'i' | 'u' => Base::Ten,
+                'x' | 'X' => Base::Hex,
+                /* 'o' | */ _ => Base::Octal,
+            };
+            let radix_mismatch = !radix_out.eq(&initial_prefix.radix_in);
+            let decrease_from_max: bool = initial_prefix.sign == -1 && *field.field_char != 'i';
+            let end = begin + convert_hints.len_digits as usize;
+
+            // convert to int if any one of these is true:
+            // - number of digits in int indicates it may be past max
+            // - we're subtracting from the max
+            // - we're converting the base
+            if convert_hints.check_past_max || decrease_from_max || radix_mismatch {
+                // radix of in and out is the same.
+                let segment = String::from(&str_in[begin..end]);
+                Intf::conv_from_segment(
+                    &segment,
+                    initial_prefix.radix_in.clone(),
+                    *field.field_char,
+                    initial_prefix.sign,
+                )
+            } else {
+                // otherwise just do a straight string copy.
+                let mut fmt_prim: FormatPrimitive = Default::default();
+
+                // this is here and not earlier because
+                // zero doesn't get a sign, and conv_from_segment
+                // creates its format primitive separately
+                if initial_prefix.sign == -1 && *field.field_char == 'i' {
+                    fmt_prim.prefix = Some(String::from("-"));
+                }
+                fmt_prim.pre_decimal = Some(String::from(&str_in[begin..end]));
+                fmt_prim
+            }
+        } else {
+            Intf::get_max(*field.field_char, initial_prefix.sign)
+        })
+    }
+    fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
+        let mut final_str: String = String::new();
+        if let Some(ref prefix) = prim.prefix {
+            final_str.push_str(prefix);
+        }
+        // integral second fields is zero-padded minimum-width
+        // which gets handled before general minimum-width
+        match prim.pre_decimal {
+            Some(ref pre_decimal) => {
+                if let Some(min) = field.second_field {
+                    let mut i = min;
+                    let len = pre_decimal.len() as u32;
+                    while i > len {
+                        final_str.push('0');
+                        i -= 1;
+                    }
+                }
+                final_str.push_str(pre_decimal);
+            }
+            None => {
+                panic!(
+                    "error, format primitives provided to int, will, incidentally under \
+                     correct behavior, always have a pre_dec value."
+                );
+            }
+        }
+        final_str
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/mod.rs.html b/src/uu_printf/tokenize/num_format/formatters/mod.rs.html new file mode 100644 index 000000000..b5653f0a4 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/mod.rs.html @@ -0,0 +1,23 @@ +mod.rs - source + +
1
+2
+3
+4
+5
+6
+7
+8
+9
+
+// spell-checker:ignore (vars) charf cninetyninehexfloatf decf floatf intf scif strf Cninety
+
+mod base_conv;
+pub mod cninetyninehexfloatf;
+pub mod decf;
+mod float_common;
+pub mod floatf;
+pub mod intf;
+pub mod scif;
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/formatters/scif.rs.html b/src/uu_printf/tokenize/num_format/formatters/scif.rs.html new file mode 100644 index 000000000..c7ae9d4a6 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/formatters/scif.rs.html @@ -0,0 +1,89 @@ +scif.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+
+// spell-checker:ignore (vars) charf cninetyninehexfloatf decf floatf intf scif strf Cninety
+
+//! formatter for %e %E scientific notation subs
+use super::super::format_field::FormatField;
+use super::super::formatter::{FormatPrimitive, Formatter, InitialPrefix};
+use super::float_common::{get_primitive_dec, primitive_to_str_common, FloatAnalysis};
+
+pub struct Scif;
+
+impl Scif {
+    pub fn new() -> Scif {
+        Scif
+    }
+}
+impl Formatter for Scif {
+    fn get_primitive(
+        &self,
+        field: &FormatField,
+        initial_prefix: &InitialPrefix,
+        str_in: &str,
+    ) -> Option<FormatPrimitive> {
+        let second_field = field.second_field.unwrap_or(6) + 1;
+        let analysis = FloatAnalysis::analyze(
+            str_in,
+            initial_prefix,
+            Some(second_field as usize + 1),
+            None,
+            false,
+        );
+        let f = get_primitive_dec(
+            initial_prefix,
+            &str_in[initial_prefix.offset..],
+            &analysis,
+            second_field as usize,
+            Some(*field.field_char == 'E'),
+        );
+        Some(f)
+    }
+    fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
+        primitive_to_str_common(prim, &field)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/mod.rs.html b/src/uu_printf/tokenize/num_format/mod.rs.html new file mode 100644 index 000000000..96d4a97d9 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/mod.rs.html @@ -0,0 +1,13 @@ +mod.rs - source + +
1
+2
+3
+4
+
+pub mod format_field;
+mod formatter;
+mod formatters;
+pub mod num_format;
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/num_format/num_format.rs.html b/src/uu_printf/tokenize/num_format/num_format.rs.html new file mode 100644 index 000000000..d8d9aa509 --- /dev/null +++ b/src/uu_printf/tokenize/num_format/num_format.rs.html @@ -0,0 +1,543 @@ +num_format.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+
+// spell-checker:ignore (vars) charf cninetyninehexfloatf decf floatf intf scif strf Cninety
+
+//! handles creating printed output for numeric substitutions
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+
+use std::env;
+use std::vec::Vec;
+
+use super::format_field::{FieldType, FormatField};
+use super::formatter::{Base, FormatPrimitive, Formatter, InitialPrefix};
+use super::formatters::cninetyninehexfloatf::CninetyNineHexFloatf;
+use super::formatters::decf::Decf;
+use super::formatters::floatf::Floatf;
+use super::formatters::intf::Intf;
+use super::formatters::scif::Scif;
+
+use crate::cli;
+
+pub fn warn_expected_numeric(pf_arg: &str) {
+    // important: keep println here not print
+    cli::err_msg(&format!("{}: expected a numeric value", pf_arg));
+}
+
+// when character constant arguments have excess characters
+// issue a warning when POSIXLY_CORRECT is not set
+fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
+    match env::var("POSIXLY_CORRECT") {
+        Ok(_) => {}
+        Err(e) => {
+            if let env::VarError::NotPresent = e {
+                cli::err_msg(&format!(
+                    "warning: {:?}: character(s) following character \
+                     constant have been ignored",
+                    &*remaining_bytes
+                ));
+            }
+        }
+    }
+}
+
+// this function looks at the first few
+// characters of an argument and returns a value if we can learn
+// a value from that (e.g. no argument? return 0, char constant? ret value)
+fn get_provided(str_in_opt: Option<&String>) -> Option<u8> {
+    const C_S_QUOTE: u8 = 39;
+    const C_D_QUOTE: u8 = 34;
+    match str_in_opt {
+        Some(str_in) => {
+            let mut byte_it = str_in.bytes();
+            if let Some(ch) = byte_it.next() {
+                match ch {
+                    C_S_QUOTE | C_D_QUOTE => {
+                        Some(match byte_it.next() {
+                            Some(second_byte) => {
+                                let mut ignored: Vec<u8> = Vec::new();
+                                for cont in byte_it {
+                                    ignored.push(cont);
+                                }
+                                if !ignored.is_empty() {
+                                    warn_char_constant_ign(ignored);
+                                }
+                                second_byte as u8
+                            }
+                            // no byte after quote
+                            None => {
+                                let so_far = (ch as u8 as char).to_string();
+                                warn_expected_numeric(&so_far);
+                                0_u8
+                            }
+                        })
+                    }
+                    // first byte is not quote
+                    _ => None, // no first byte
+                }
+            } else {
+                Some(0_u8)
+            }
+        }
+        None => Some(0),
+    }
+}
+
+// takes a string and returns
+// a sign,
+// a base,
+// and an offset for index after all
+//  initial spacing, sign, base prefix, and leading zeroes
+fn get_initial_prefix(str_in: &str, field_type: &FieldType) -> InitialPrefix {
+    let mut str_it = str_in.chars();
+    let mut ret = InitialPrefix {
+        radix_in: Base::Ten,
+        sign: 1,
+        offset: 0,
+    };
+    let mut top_char = str_it.next();
+    // skip spaces and ensure top_char is the first non-space char
+    // (or None if none exists)
+    while let Some(' ') = top_char {
+        ret.offset += 1;
+        top_char = str_it.next();
+    }
+    // parse sign
+    match top_char {
+        Some('+') => {
+            ret.offset += 1;
+            top_char = str_it.next();
+        }
+        Some('-') => {
+            ret.sign = -1;
+            ret.offset += 1;
+            top_char = str_it.next();
+        }
+        _ => {}
+    }
+    // we want to exit with offset being
+    // the index of the first non-zero
+    // digit before the decimal point or
+    // if there is none, the zero before the
+    // decimal point, or, if there is none,
+    // the decimal point.
+
+    // while we are determining the offset
+    // we will ensure as a convention
+    // the offset is always on the first character
+    // that we are yet unsure if it is the
+    // final offset. If the zero could be before
+    // a decimal point we don't move past the zero.
+    let mut is_hex = false;
+    if Some('0') == top_char {
+        if let Some(base) = str_it.next() {
+            // lead zeroes can only exist in
+            // octal and hex base
+            let mut do_clean_lead_zeroes = false;
+            match base {
+                'x' | 'X' => {
+                    is_hex = true;
+                    ret.offset += 2;
+                    ret.radix_in = Base::Hex;
+                    do_clean_lead_zeroes = true;
+                }
+                e @ '0'..='9' => {
+                    ret.offset += 1;
+                    if let FieldType::Intf = *field_type {
+                        ret.radix_in = Base::Octal;
+                    }
+                    if e == '0' {
+                        do_clean_lead_zeroes = true;
+                    }
+                }
+                _ => {}
+            }
+            if do_clean_lead_zeroes {
+                let mut first = true;
+                for ch_zero in str_it {
+                    // see notes on offset above:
+                    // this is why the offset for octal and decimal numbers
+                    // that reach this branch is 1 even though
+                    // they have already eaten the characters '00'
+                    // this is also why when hex encounters its
+                    // first zero it does not move its offset
+                    // forward because it does not know for sure
+                    // that it's current offset (of that zero)
+                    // is not the final offset,
+                    // whereas at that point octal knows its
+                    // current offset is not the final offset.
+                    match ch_zero {
+                        '0' => {
+                            if !(is_hex && first) {
+                                ret.offset += 1;
+                            }
+                        }
+                        // if decimal, keep last zero if one exists
+                        // (it's possible for last zero to
+                        // not exist at this branch if we're in hex input)
+                        '.' => break,
+                        // other digit, etc.
+                        _ => {
+                            if !(is_hex && first) {
+                                ret.offset += 1;
+                            }
+                            break;
+                        }
+                    }
+                    if first {
+                        first = false;
+                    }
+                }
+            }
+        }
+    }
+    ret
+}
+
+// this is the function a Sub's print will delegate to
+// if it is a numeric field, passing the field details
+// and an iterator to the argument
+pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<String> {
+    let field_char = field.field_char;
+
+    // num format mainly operates by further delegating to one of
+    // several Formatter structs depending on the field
+    // see formatter.rs for more details
+
+    // to do switch to static dispatch
+    let formatter: Box<dyn Formatter> = match *field.field_type {
+        FieldType::Intf => Box::new(Intf::new()),
+        FieldType::Floatf => Box::new(Floatf::new()),
+        FieldType::CninetyNineHexFloatf => Box::new(CninetyNineHexFloatf::new()),
+        FieldType::Scif => Box::new(Scif::new()),
+        FieldType::Decf => Box::new(Decf::new()),
+        _ => {
+            panic!("asked to do num format with non-num field type");
+        }
+    };
+    let prim_opt=
+        // if we can get an assumed value from looking at the first
+        // few characters, use that value to create the FormatPrimitive
+        if let Some(provided_num) = get_provided(in_str_opt) {
+            let mut tmp : FormatPrimitive = Default::default();
+            match field_char {
+                'u' | 'i' | 'd' => {
+                    tmp.pre_decimal = Some(
+                        format!("{}", provided_num));
+                },
+                'x' | 'X' => {
+                    tmp.pre_decimal = Some(
+                        format!("{:x}", provided_num));
+                },
+                'o' => {
+                    tmp.pre_decimal = Some(
+                        format!("{:o}", provided_num));
+                },
+                'e' | 'E' | 'g' | 'G' => {
+                    let as_str = format!("{}", provided_num);
+                    let initial_prefix = get_initial_prefix(
+                        &as_str,
+                        field.field_type
+                    );
+                    tmp=formatter.get_primitive(field, &initial_prefix, &as_str)
+                        .expect("err during default provided num");
+                },
+                _ => {
+                    tmp.pre_decimal = Some(
+                        format!("{}", provided_num));
+                    tmp.post_decimal = Some(String::from("0"));
+                }
+            }
+            Some(tmp)
+        } else {
+            // otherwise we'll interpret the argument as a number
+            // using the appropriate Formatter
+            let in_str = in_str_opt.expect(
+                "please send the devs this message:
+                \n get_provided is failing to ret as Some(0) on no str ");
+            // first get information about the beginning of the
+            // numeric argument that would be useful for
+            // any formatter (int or float)
+            let initial_prefix = get_initial_prefix(
+                in_str,
+                field.field_type
+            );
+            // then get the FormatPrimitive from the Formatter
+            formatter.get_primitive(field, &initial_prefix, in_str)
+        };
+    // if we have a formatPrimitive, print its results
+    // according to the field-char appropriate Formatter
+    prim_opt.map(|prim| formatter.primitive_to_str(&prim, field.clone()))
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/sub.rs.html b/src/uu_printf/tokenize/sub.rs.html new file mode 100644 index 000000000..3a0ca8a75 --- /dev/null +++ b/src/uu_printf/tokenize/sub.rs.html @@ -0,0 +1,841 @@ +sub.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+
+// spell-checker:ignore (vars) charf decf floatf intf scif strf Cninety
+
+//! Sub is a token that represents a
+//! segment of the format string that is a substitution
+//! it is created by Sub's implementation of the Tokenizer trait
+//! Subs which have numeric field chars make use of the num_format
+//! submodule
+use itertools::{put_back_n, PutBackN};
+use std::iter::Peekable;
+use std::process::exit;
+use std::slice::Iter;
+use std::str::Chars;
+// use std::collections::HashSet;
+
+use super::num_format::format_field::{FieldType, FormatField};
+use super::num_format::num_format;
+use super::token;
+use super::unescaped_text::UnescapedText;
+use crate::cli;
+
+fn err_conv(sofar: &str) {
+    cli::err_msg(&format!("%{}: invalid conversion specification", sofar));
+    exit(cli::EXIT_ERR);
+}
+
+fn convert_asterisk_arg_int(asterisk_arg: &str) -> isize {
+    // this is a costly way to parse the
+    // args used for asterisk values into integers
+    // from various bases. Actually doing it correctly
+    // (going through the pipeline to intf, but returning
+    // the integer instead of writing it to string and then
+    // back) is on the refactoring TODO
+    let field_type = FieldType::Intf;
+    let field_char = 'i';
+    let field_info = FormatField {
+        min_width: Some(0),
+        second_field: Some(0),
+        orig: &asterisk_arg.to_string(),
+        field_type: &field_type,
+        field_char: &field_char,
+    };
+    num_format::num_format(&field_info, Some(&asterisk_arg.to_string()))
+        .unwrap()
+        .parse::<isize>()
+        .unwrap()
+}
+
+pub enum CanAsterisk<T> {
+    Fixed(T),
+    Asterisk,
+}
+
+// Sub is a tokenizer which creates tokens
+// for substitution segments of a format string
+pub struct Sub {
+    min_width: CanAsterisk<Option<isize>>,
+    second_field: CanAsterisk<Option<u32>>,
+    field_char: char,
+    field_type: FieldType,
+    orig: String,
+}
+impl Sub {
+    pub fn new(
+        min_width: CanAsterisk<Option<isize>>,
+        second_field: CanAsterisk<Option<u32>>,
+        field_char: char,
+        orig: String,
+    ) -> Sub {
+        // for more dry printing, field characters are grouped
+        // in initialization of token.
+        let field_type = match field_char {
+            's' | 'b' => FieldType::Strf,
+            'd' | 'i' | 'u' | 'o' | 'x' | 'X' => FieldType::Intf,
+            'f' | 'F' => FieldType::Floatf,
+            'a' | 'A' => FieldType::CninetyNineHexFloatf,
+            'e' | 'E' => FieldType::Scif,
+            'g' | 'G' => FieldType::Decf,
+            'c' => FieldType::Charf,
+            _ => {
+                // should be unreachable.
+                println!("Invalid field type");
+                exit(cli::EXIT_ERR);
+            }
+        };
+        Sub {
+            min_width,
+            second_field,
+            field_char,
+            field_type,
+            orig,
+        }
+    }
+}
+
+struct SubParser {
+    min_width_tmp: Option<String>,
+    min_width_is_asterisk: bool,
+    past_decimal: bool,
+    second_field_tmp: Option<String>,
+    second_field_is_asterisk: bool,
+    specifiers_found: bool,
+    field_char: Option<char>,
+    text_so_far: String,
+}
+
+impl SubParser {
+    fn new() -> SubParser {
+        SubParser {
+            min_width_tmp: None,
+            min_width_is_asterisk: false,
+            past_decimal: false,
+            second_field_tmp: None,
+            second_field_is_asterisk: false,
+            specifiers_found: false,
+            field_char: None,
+            text_so_far: String::new(),
+        }
+    }
+    fn from_it(
+        it: &mut PutBackN<Chars>,
+        args: &mut Peekable<Iter<String>>,
+    ) -> Option<Box<dyn token::Token>> {
+        let mut parser = SubParser::new();
+        if parser.sub_vals_retrieved(it) {
+            let t: Box<dyn token::Token> = SubParser::build_token(parser);
+            t.print(args);
+            Some(t)
+        } else {
+            None
+        }
+    }
+    fn build_token(parser: SubParser) -> Box<dyn token::Token> {
+        // not a self method so as to allow move of sub-parser vals.
+        // return new Sub struct as token
+        let t: Box<dyn token::Token> = Box::new(Sub::new(
+            if parser.min_width_is_asterisk {
+                CanAsterisk::Asterisk
+            } else {
+                CanAsterisk::Fixed(parser.min_width_tmp.map(|x| x.parse::<isize>().unwrap()))
+            },
+            if parser.second_field_is_asterisk {
+                CanAsterisk::Asterisk
+            } else {
+                CanAsterisk::Fixed(parser.second_field_tmp.map(|x| x.parse::<u32>().unwrap()))
+            },
+            parser.field_char.unwrap(),
+            parser.text_so_far,
+        ));
+        t
+    }
+    fn sub_vals_retrieved(&mut self, it: &mut PutBackN<Chars>) -> bool {
+        if !SubParser::successfully_eat_prefix(it, &mut self.text_so_far) {
+            return false;
+        }
+        // this fn in particular is much longer than it needs to be
+        // .could get a lot
+        // of code savings just by cleaning it up. shouldn't use a regex
+        // though, as we want to mimic the original behavior of printing
+        // the field as interpreted up until the error in the field.
+
+        let mut legal_fields = vec![
+            // 'a', 'A', //c99 hex float implementation not yet complete
+            'b', 'c', 'd', 'e', 'E', 'f', 'F', 'g', 'G', 'i', 'o', 's', 'u', 'x', 'X',
+        ];
+        let mut specifiers = vec!['h', 'j', 'l', 'L', 't', 'z'];
+        legal_fields.sort_unstable();
+        specifiers.sort_unstable();
+
+        // divide substitution from %([0-9]+)?(.[0-9+])?([a-zA-Z])
+        // into min_width, second_field, field_char
+        for ch in it {
+            self.text_so_far.push(ch);
+            match ch as char {
+                '-' | '*' | '0'..='9' => {
+                    if !self.past_decimal {
+                        if self.min_width_is_asterisk || self.specifiers_found {
+                            err_conv(&self.text_so_far);
+                        }
+                        if self.min_width_tmp.is_none() {
+                            self.min_width_tmp = Some(String::new());
+                        }
+                        match self.min_width_tmp.as_mut() {
+                            Some(x) => {
+                                if (ch == '-' || ch == '*') && !x.is_empty() {
+                                    err_conv(&self.text_so_far);
+                                }
+                                if ch == '*' {
+                                    self.min_width_is_asterisk = true;
+                                }
+                                x.push(ch);
+                            }
+                            None => {
+                                panic!("should be unreachable");
+                            }
+                        }
+                    } else {
+                        // second field should never have a
+                        // negative value
+                        if self.second_field_is_asterisk || ch == '-' || self.specifiers_found {
+                            err_conv(&self.text_so_far);
+                        }
+                        if self.second_field_tmp.is_none() {
+                            self.second_field_tmp = Some(String::new());
+                        }
+                        match self.second_field_tmp.as_mut() {
+                            Some(x) => {
+                                if ch == '*' && !x.is_empty() {
+                                    err_conv(&self.text_so_far);
+                                }
+                                if ch == '*' {
+                                    self.second_field_is_asterisk = true;
+                                }
+                                x.push(ch);
+                            }
+                            None => {
+                                panic!("should be unreachable");
+                            }
+                        }
+                    }
+                }
+                '.' => {
+                    if !self.past_decimal {
+                        self.past_decimal = true;
+                    } else {
+                        err_conv(&self.text_so_far);
+                    }
+                }
+                x if legal_fields.binary_search(&x).is_ok() => {
+                    self.field_char = Some(ch);
+                    self.text_so_far.push(ch);
+                    break;
+                }
+                x if specifiers.binary_search(&x).is_ok() => {
+                    if !self.past_decimal {
+                        self.past_decimal = true;
+                    }
+                    if !self.specifiers_found {
+                        self.specifiers_found = true;
+                    }
+                }
+                _ => {
+                    err_conv(&self.text_so_far);
+                }
+            }
+        }
+        if self.field_char.is_none() {
+            err_conv(&self.text_so_far);
+        }
+        let field_char_retrieved = self.field_char.unwrap();
+        if self.past_decimal && self.second_field_tmp.is_none() {
+            self.second_field_tmp = Some(String::from("0"));
+        }
+        self.validate_field_params(field_char_retrieved);
+        // if the dot is provided without a second field
+        // printf interprets it as 0.
+        if let Some(x) = self.second_field_tmp.as_mut() {
+            if x.is_empty() {
+                self.min_width_tmp = Some(String::from("0"));
+            }
+        }
+
+        true
+    }
+    fn successfully_eat_prefix(it: &mut PutBackN<Chars>, text_so_far: &mut String) -> bool {
+        // get next two chars,
+        // if they're '%%' we're not tokenizing it
+        // else put chars back
+        let preface = it.next();
+        let n_ch = it.next();
+        if preface == Some('%') && n_ch != Some('%') {
+            match n_ch {
+                Some(x) => {
+                    it.put_back(x);
+                    true
+                }
+                None => {
+                    text_so_far.push('%');
+                    err_conv(text_so_far);
+                    false
+                }
+            }
+        } else {
+            if let Some(x) = n_ch {
+                it.put_back(x)
+            };
+            if let Some(x) = preface {
+                it.put_back(x)
+            };
+            false
+        }
+    }
+    fn validate_field_params(&self, field_char: char) {
+        // check for illegal combinations here when possible vs
+        // on each application so we check less per application
+        // to do: move these checks to Sub::new
+        if (field_char == 's' && self.min_width_tmp == Some(String::from("0")))
+            || (field_char == 'c'
+                && (self.min_width_tmp == Some(String::from("0")) || self.past_decimal))
+            || (field_char == 'b'
+                && (self.min_width_tmp.is_some()
+                    || self.past_decimal
+                    || self.second_field_tmp.is_some()))
+        {
+            err_conv(&self.text_so_far);
+        }
+    }
+}
+
+impl token::Tokenizer for Sub {
+    fn from_it(
+        it: &mut PutBackN<Chars>,
+        args: &mut Peekable<Iter<String>>,
+    ) -> Option<Box<dyn token::Token>> {
+        SubParser::from_it(it, args)
+    }
+}
+impl token::Token for Sub {
+    fn print(&self, pf_args_it: &mut Peekable<Iter<String>>) {
+        let field = FormatField {
+            min_width: match self.min_width {
+                CanAsterisk::Fixed(x) => x,
+                CanAsterisk::Asterisk => {
+                    match pf_args_it.next() {
+                        // temporary, use intf.rs instead
+                        Some(x) => Some(convert_asterisk_arg_int(x)),
+                        None => Some(0),
+                    }
+                }
+            },
+            second_field: match self.second_field {
+                CanAsterisk::Fixed(x) => x,
+                CanAsterisk::Asterisk => {
+                    match pf_args_it.next() {
+                        // temporary, use intf.rs instead
+                        Some(x) => {
+                            let result = convert_asterisk_arg_int(x);
+                            if result < 0 {
+                                None
+                            } else {
+                                Some(result as u32)
+                            }
+                        }
+                        None => Some(0),
+                    }
+                }
+            },
+            field_char: &self.field_char,
+            field_type: &self.field_type,
+            orig: &self.orig,
+        };
+        let pf_arg = pf_args_it.next();
+
+        // minimum width is handled independently of actual
+        // field char
+        let pre_min_width_opt: Option<String> = match *field.field_type {
+            // if %s just return arg
+            // if %b use UnescapedText module's unescape-fn
+            // if %c return first char of arg
+            FieldType::Strf | FieldType::Charf => {
+                match pf_arg {
+                    Some(arg_string) => {
+                        match *field.field_char {
+                            's' => Some(match field.second_field {
+                                Some(max) => String::from(&arg_string[..max as usize]),
+                                None => arg_string.clone(),
+                            }),
+                            'b' => {
+                                let mut a_it = put_back_n(arg_string.chars());
+                                UnescapedText::from_it_core(&mut a_it, true);
+                                None
+                            }
+                            // for 'c': get iter of string vals,
+                            // get opt<char> of first val
+                            // and map it to opt<String>
+                            /* 'c' | */
+                            _ => arg_string.chars().next().map(|x| x.to_string()),
+                        }
+                    }
+                    None => None,
+                }
+            }
+            _ => {
+                // non string/char fields are delegated to num_format
+                num_format::num_format(&field, pf_arg)
+            }
+        };
+        if let Some(pre_min_width) = pre_min_width_opt {
+            // if have a string, print it, ensuring minimum width is met.
+            print!(
+                "{}",
+                match field.min_width {
+                    Some(min_width) => {
+                        let diff: isize = min_width.abs() as isize - pre_min_width.len() as isize;
+                        if diff > 0 {
+                            let mut final_str = String::new();
+                            // definitely more efficient ways
+                            //  to do this.
+                            let pad_before = min_width > 0;
+                            if !pad_before {
+                                final_str.push_str(&pre_min_width);
+                            }
+                            for _ in 0..diff {
+                                final_str.push(' ');
+                            }
+                            if pad_before {
+                                final_str.push_str(&pre_min_width);
+                            }
+                            final_str
+                        } else {
+                            pre_min_width
+                        }
+                    }
+                    None => pre_min_width,
+                }
+            );
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/token.rs.html b/src/uu_printf/tokenize/token.rs.html new file mode 100644 index 000000000..47e142ee3 --- /dev/null +++ b/src/uu_printf/tokenize/token.rs.html @@ -0,0 +1,67 @@ +token.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+
+//! Traits and enums dealing with Tokenization of printf Format String
+use itertools::PutBackN;
+use std::iter::Peekable;
+use std::slice::Iter;
+use std::str::Chars;
+
+// A token object is an object that can print the expected output
+// of a contiguous segment of the format string, and
+// requires at most 1 argument
+pub trait Token {
+    fn print(&self, args: &mut Peekable<Iter<String>>);
+}
+
+// A tokenizer object is an object that takes an iterator
+// at a position in a format string, and sees whether
+// it can return a token of a type it knows how to produce
+// if so, return the token, move the iterator past the
+// format string text the token represents, and if an
+// argument is used move the argument iter forward one
+
+// creating token of a format string segment should also cause
+// printing of that token's value. Essentially tokenizing
+// a whole format string will print the format string and consume
+// a number of arguments equal to the number of argument-using tokens
+
+pub trait Tokenizer {
+    fn from_it(
+        it: &mut PutBackN<Chars>,
+        args: &mut Peekable<Iter<String>>,
+    ) -> Option<Box<dyn Token>>;
+}
+
+
\ No newline at end of file diff --git a/src/uu_printf/tokenize/unescaped_text.rs.html b/src/uu_printf/tokenize/unescaped_text.rs.html new file mode 100644 index 000000000..9ec208770 --- /dev/null +++ b/src/uu_printf/tokenize/unescaped_text.rs.html @@ -0,0 +1,519 @@ +unescaped_text.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+
+//! UnescapedText is a tokenizer impl
+//! for tokenizing character literals,
+//! and escaped character literals (of allowed escapes),
+//! into an unescaped text byte array
+
+// spell-checker:ignore (ToDO) retval hexchars octals printf's bvec vals coreutil addchar eval bytecode
+
+use itertools::PutBackN;
+use std::char::from_u32;
+use std::iter::Peekable;
+use std::process::exit;
+use std::slice::Iter;
+use std::str::Chars;
+
+use super::token;
+
+use crate::cli;
+
+pub struct UnescapedText(Vec<u8>);
+impl UnescapedText {
+    fn new() -> UnescapedText {
+        UnescapedText(Vec::new())
+    }
+    // take an iterator to the format string
+    // consume between min and max chars
+    // and return it as a base-X number
+    fn base_to_u32(min_chars: u8, max_chars: u8, base: u32, it: &mut PutBackN<Chars>) -> u32 {
+        let mut retval: u32 = 0;
+        let mut found = 0;
+        while found < max_chars {
+            // if end of input break
+            let nc = it.next();
+            match nc {
+                Some(digit) => {
+                    // if end of hexchars break
+                    match digit.to_digit(base) {
+                        Some(d) => {
+                            found += 1;
+                            retval *= base;
+                            retval += d;
+                        }
+                        None => {
+                            it.put_back(digit);
+                            break;
+                        }
+                    }
+                }
+                None => {
+                    break;
+                }
+            }
+        }
+        if found < min_chars {
+            // only ever expected for hex
+            println!("missing hexadecimal number in escape"); //todo stderr
+            exit(cli::EXIT_ERR);
+        }
+        retval
+    }
+    // validates against valid
+    // IEC 10646 vals - these values
+    // are pinned against the more popular
+    // printf so as to not disrupt when
+    // dropped-in as a replacement.
+    fn validate_iec(val: u32, eight_word: bool) {
+        let mut preface = 'u';
+        let leading_zeros = if eight_word {
+            preface = 'U';
+            8
+        } else {
+            4
+        };
+        let err_msg = format!(
+            "invalid universal character name {0}{1:02$x}",
+            preface, val, leading_zeros
+        );
+        if (val < 159 && (val != 36 && val != 64 && val != 96)) || (val > 55296 && val < 57343) {
+            println!("{}", err_msg); //todo stderr
+            exit(cli::EXIT_ERR);
+        }
+    }
+    // pass an iterator that succeeds an '/',
+    // and process the remaining character
+    // adding the unescaped bytes
+    // to the passed byte_vec
+    // in subs_mode change octal behavior
+    fn handle_escaped(byte_vec: &mut Vec<u8>, it: &mut PutBackN<Chars>, subs_mode: bool) {
+        let ch = it.next().unwrap_or('\\');
+        match ch {
+            '0'..='9' | 'x' => {
+                let min_len = 1;
+                let mut max_len = 2;
+                let mut base = 16;
+                let ignore = false;
+                match ch {
+                    'x' => {}
+                    e @ '0'..='9' => {
+                        max_len = 3;
+                        base = 8;
+                        // in practice, gnu coreutils printf
+                        // interprets octals without a
+                        // leading zero in %b
+                        // but it only skips leading zeros
+                        // in %b mode.
+                        // if we ever want to match gnu coreutil
+                        // printf's docs instead of its behavior
+                        // we'd set this to true.
+                        // if subs_mode && e != '0'
+                        //  { ignore = true; }
+                        if !subs_mode || e != '0' {
+                            it.put_back(ch);
+                        }
+                    }
+                    _ => {}
+                }
+                if !ignore {
+                    let val = (UnescapedText::base_to_u32(min_len, max_len, base, it) % 256) as u8;
+                    byte_vec.push(val);
+                    let bvec = [val];
+                    cli::flush_bytes(&bvec);
+                } else {
+                    byte_vec.push(ch as u8);
+                }
+            }
+            e => {
+                // only for hex and octal
+                // is byte encoding specified.
+                // otherwise, why not leave the door open
+                // for other encodings unless it turns out
+                // a bottleneck.
+                let mut s = String::new();
+                let ch = match e {
+                    '\\' => '\\',
+                    '"' => '"',
+                    'n' => '\n',
+                    'r' => '\r',
+                    't' => '\t',
+                    // bell
+                    'a' => '\x07',
+                    // backspace
+                    'b' => '\x08',
+                    // vertical tab
+                    'v' => '\x0B',
+                    // form feed
+                    'f' => '\x0C',
+                    // escape character
+                    'e' => '\x1B',
+                    'c' => exit(cli::EXIT_OK),
+                    'u' | 'U' => {
+                        let len = match e {
+                            'u' => 4,
+                            /* 'U' | */ _ => 8,
+                        };
+                        let val = UnescapedText::base_to_u32(len, len, 16, it);
+                        UnescapedText::validate_iec(val, false);
+                        if let Some(c) = from_u32(val) {
+                            c
+                        } else {
+                            '-'
+                        }
+                    }
+                    _ => {
+                        s.push('\\');
+                        ch
+                    }
+                };
+                s.push(ch);
+                cli::flush_str(&s);
+                byte_vec.extend(s.bytes());
+            }
+        };
+    }
+
+    // take an iterator to a string,
+    // and return a wrapper around a Vec<u8> of unescaped bytes
+    // break on encounter of sub symbol ('%[^%]') unless called
+    // through %b subst.
+    pub fn from_it_core(
+        it: &mut PutBackN<Chars>,
+        subs_mode: bool,
+    ) -> Option<Box<dyn token::Token>> {
+        let mut addchar = false;
+        let mut new_text = UnescapedText::new();
+        let mut tmp_str = String::new();
+        {
+            let new_vec: &mut Vec<u8> = &mut (new_text.0);
+            while let Some(ch) = it.next() {
+                if !addchar {
+                    addchar = true;
+                }
+                match ch as char {
+                    x if x != '\\' && x != '%' => {
+                        // lazy branch eval
+                        // remember this fn could be called
+                        // many times in a single exec through %b
+                        cli::flush_char(ch);
+                        tmp_str.push(ch);
+                    }
+                    '\\' => {
+                        // the literal may be a literal bytecode
+                        // and not valid utf-8. Str only supports
+                        // valid utf-8.
+                        // if we find the unnecessary drain
+                        // on non hex or octal escapes is costly
+                        // then we can make it faster/more complex
+                        // with as-necessary draining.
+                        if !tmp_str.is_empty() {
+                            new_vec.extend(tmp_str.bytes());
+                            tmp_str = String::new();
+                        }
+                        UnescapedText::handle_escaped(new_vec, it, subs_mode)
+                    }
+                    x if x == '%' && !subs_mode => {
+                        if let Some(follow) = it.next() {
+                            if follow == '%' {
+                                cli::flush_char(ch);
+                                tmp_str.push(ch);
+                            } else {
+                                it.put_back(follow);
+                                it.put_back(ch);
+                                break;
+                            }
+                        } else {
+                            it.put_back(ch);
+                            break;
+                        }
+                    }
+                    _ => {
+                        cli::flush_char(ch);
+                        tmp_str.push(ch);
+                    }
+                }
+            }
+            if !tmp_str.is_empty() {
+                new_vec.extend(tmp_str.bytes());
+            }
+        }
+        if addchar {
+            Some(Box::new(new_text))
+        } else {
+            None
+        }
+    }
+}
+impl token::Tokenizer for UnescapedText {
+    fn from_it(
+        it: &mut PutBackN<Chars>,
+        _: &mut Peekable<Iter<String>>,
+    ) -> Option<Box<dyn token::Token>> {
+        UnescapedText::from_it_core(it, false)
+    }
+}
+impl token::Token for UnescapedText {
+    fn print(&self, _: &mut Peekable<Iter<String>>) {
+        cli::flush_bytes(&self.0[..]);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_ptx/ptx.rs.html b/src/uu_ptx/ptx.rs.html new file mode 100644 index 000000000..217675886 --- /dev/null +++ b/src/uu_ptx/ptx.rs.html @@ -0,0 +1,1577 @@ +ptx.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Dorota Kapturkiewicz <dokaptur@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDOs) corasick memchr Roff trunc oset iset
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use regex::Regex;
+use std::cmp;
+use std::collections::{BTreeSet, HashMap, HashSet};
+use std::default::Default;
+use std::fs::File;
+use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
+use uucore::InvalidEncodingHandling;
+
+static NAME: &str = "ptx";
+static BRIEF: &str = "Usage: ptx [OPTION]... [INPUT]...   (without -G) or: \
+                 ptx -G [OPTION]... [INPUT [OUTPUT]] \n Output a permuted index, \
+                 including context, of the words in the input files. \n\n Mandatory \
+                 arguments to long options are mandatory for short options too.\n
+                 With no FILE, or when FILE is -, read standard input. \
+                Default is '-F /'.";
+
+#[derive(Debug)]
+enum OutFormat {
+    Dumb,
+    Roff,
+    Tex,
+}
+
+#[derive(Debug)]
+struct Config {
+    format: OutFormat,
+    gnu_ext: bool,
+    auto_ref: bool,
+    input_ref: bool,
+    right_ref: bool,
+    ignore_case: bool,
+    macro_name: String,
+    trunc_str: String,
+    context_regex: String,
+    line_width: usize,
+    gap_size: usize,
+}
+
+impl Default for Config {
+    fn default() -> Config {
+        Config {
+            format: OutFormat::Dumb,
+            gnu_ext: true,
+            auto_ref: false,
+            input_ref: false,
+            right_ref: false,
+            ignore_case: false,
+            macro_name: "xx".to_owned(),
+            trunc_str: "/".to_owned(),
+            context_regex: "\\w+".to_owned(),
+            line_width: 72,
+            gap_size: 3,
+        }
+    }
+}
+
+fn read_word_filter_file(matches: &clap::ArgMatches, option: &str) -> HashSet<String> {
+    let filename = matches
+        .value_of(option)
+        .expect("parsing options failed!")
+        .to_string();
+    let reader = BufReader::new(crash_if_err!(1, File::open(filename)));
+    let mut words: HashSet<String> = HashSet::new();
+    for word in reader.lines() {
+        words.insert(crash_if_err!(1, word));
+    }
+    words
+}
+
+#[derive(Debug)]
+struct WordFilter {
+    only_specified: bool,
+    ignore_specified: bool,
+    only_set: HashSet<String>,
+    ignore_set: HashSet<String>,
+    word_regex: String,
+}
+
+impl WordFilter {
+    fn new(matches: &clap::ArgMatches, config: &Config) -> WordFilter {
+        let (o, oset): (bool, HashSet<String>) = if matches.is_present(options::ONLY_FILE) {
+            (true, read_word_filter_file(matches, options::ONLY_FILE))
+        } else {
+            (false, HashSet::new())
+        };
+        let (i, iset): (bool, HashSet<String>) = if matches.is_present(options::IGNORE_FILE) {
+            (true, read_word_filter_file(matches, options::IGNORE_FILE))
+        } else {
+            (false, HashSet::new())
+        };
+        if matches.is_present(options::BREAK_FILE) {
+            crash!(1, "-b not implemented yet");
+        }
+        // Ignore empty string regex from cmd-line-args
+        let arg_reg: Option<String> = if matches.is_present(options::WORD_REGEXP) {
+            match matches.value_of(options::WORD_REGEXP) {
+                Some(v) => {
+                    if v.is_empty() {
+                        None
+                    } else {
+                        Some(v.to_string())
+                    }
+                }
+                None => None,
+            }
+        } else {
+            None
+        };
+        let reg = match arg_reg {
+            Some(arg_reg) => arg_reg,
+            None => {
+                if config.gnu_ext {
+                    "\\w+".to_owned()
+                } else {
+                    "[^ \t\n]+".to_owned()
+                }
+            }
+        };
+        WordFilter {
+            only_specified: o,
+            ignore_specified: i,
+            only_set: oset,
+            ignore_set: iset,
+            word_regex: reg,
+        }
+    }
+}
+
+#[derive(Debug, PartialOrd, PartialEq, Eq, Ord)]
+struct WordRef {
+    word: String,
+    global_line_nr: usize,
+    local_line_nr: usize,
+    position: usize,
+    position_end: usize,
+    filename: String,
+}
+
+fn get_config(matches: &clap::ArgMatches) -> Config {
+    let mut config: Config = Default::default();
+    let err_msg = "parsing options failed";
+    if matches.is_present(options::TRADITIONAL) {
+        config.gnu_ext = false;
+        config.format = OutFormat::Roff;
+        config.context_regex = "[^ \t\n]+".to_owned();
+    } else {
+        crash!(1, "GNU extensions not implemented yet");
+    }
+    if matches.is_present(options::SENTENCE_REGEXP) {
+        crash!(1, "-S not implemented yet");
+    }
+    config.auto_ref = matches.is_present(options::AUTO_REFERENCE);
+    config.input_ref = matches.is_present(options::REFERENCES);
+    config.right_ref &= matches.is_present(options::RIGHT_SIDE_REFS);
+    config.ignore_case = matches.is_present(options::IGNORE_CASE);
+    if matches.is_present(options::MACRO_NAME) {
+        config.macro_name = matches
+            .value_of(options::MACRO_NAME)
+            .expect(err_msg)
+            .to_string();
+    }
+    if matches.is_present(options::FLAG_TRUNCATION) {
+        config.trunc_str = matches
+            .value_of(options::FLAG_TRUNCATION)
+            .expect(err_msg)
+            .to_string();
+    }
+    if matches.is_present(options::WIDTH) {
+        let width_str = matches.value_of(options::WIDTH).expect(err_msg).to_string();
+        config.line_width = crash_if_err!(1, (&width_str).parse::<usize>());
+    }
+    if matches.is_present(options::GAP_SIZE) {
+        let gap_str = matches
+            .value_of(options::GAP_SIZE)
+            .expect(err_msg)
+            .to_string();
+        config.gap_size = crash_if_err!(1, (&gap_str).parse::<usize>());
+    }
+    if matches.is_present(options::FORMAT_ROFF) {
+        config.format = OutFormat::Roff;
+    }
+    if matches.is_present(options::FORMAT_TEX) {
+        config.format = OutFormat::Tex;
+    }
+    config
+}
+
+struct FileContent {
+    lines: Vec<String>,
+    chars_lines: Vec<Vec<char>>,
+    offset: usize,
+}
+
+type FileMap = HashMap<String, FileContent>;
+
+fn read_input(input_files: &[String], config: &Config) -> FileMap {
+    let mut file_map: FileMap = HashMap::new();
+    let mut files = Vec::new();
+    if input_files.is_empty() {
+        files.push("-");
+    } else if config.gnu_ext {
+        for file in input_files {
+            files.push(file);
+        }
+    } else {
+        files.push(&input_files[0]);
+    }
+    let mut offset: usize = 0;
+    for filename in files {
+        let reader: BufReader<Box<dyn Read>> = BufReader::new(if filename == "-" {
+            Box::new(stdin())
+        } else {
+            let file = crash_if_err!(1, File::open(filename));
+            Box::new(file)
+        });
+        let lines: Vec<String> = reader.lines().map(|x| crash_if_err!(1, x)).collect();
+
+        // Indexing UTF-8 string requires walking from the beginning, which can hurts performance badly when the line is long.
+        // Since we will be jumping around the line a lot, we dump the content into a Vec<char>, which can be indexed in constant time.
+        let chars_lines: Vec<Vec<char>> = lines.iter().map(|x| x.chars().collect()).collect();
+        let size = lines.len();
+        file_map.insert(
+            filename.to_owned(),
+            FileContent {
+                lines,
+                chars_lines,
+                offset,
+            },
+        );
+        offset += size
+    }
+    file_map
+}
+
+/// Go through every lines in the input files and record each match occurrence as a `WordRef`.
+fn create_word_set(config: &Config, filter: &WordFilter, file_map: &FileMap) -> BTreeSet<WordRef> {
+    let reg = Regex::new(&filter.word_regex).unwrap();
+    let ref_reg = Regex::new(&config.context_regex).unwrap();
+    let mut word_set: BTreeSet<WordRef> = BTreeSet::new();
+    for (file, lines) in file_map.iter() {
+        let mut count: usize = 0;
+        let offs = lines.offset;
+        for line in &lines.lines {
+            // if -r, exclude reference from word set
+            let (ref_beg, ref_end) = match ref_reg.find(line) {
+                Some(x) => (x.start(), x.end()),
+                None => (0, 0),
+            };
+            // match words with given regex
+            for mat in reg.find_iter(line) {
+                let (beg, end) = (mat.start(), mat.end());
+                if config.input_ref && ((beg, end) == (ref_beg, ref_end)) {
+                    continue;
+                }
+                let mut word = line[beg..end].to_owned();
+                if filter.only_specified && !(filter.only_set.contains(&word)) {
+                    continue;
+                }
+                if filter.ignore_specified && filter.ignore_set.contains(&word) {
+                    continue;
+                }
+                if config.ignore_case {
+                    word = word.to_lowercase();
+                }
+                word_set.insert(WordRef {
+                    word,
+                    filename: file.clone(),
+                    global_line_nr: offs + count,
+                    local_line_nr: count,
+                    position: beg,
+                    position_end: end,
+                });
+            }
+            count += 1;
+        }
+    }
+    word_set
+}
+
+fn get_reference(config: &Config, word_ref: &WordRef, line: &str, context_reg: &Regex) -> String {
+    if config.auto_ref {
+        format!("{}:{}", word_ref.filename, word_ref.local_line_nr + 1)
+    } else if config.input_ref {
+        let (beg, end) = match context_reg.find(line) {
+            Some(x) => (x.start(), x.end()),
+            None => (0, 0),
+        };
+        line[beg..end].to_string()
+    } else {
+        String::new()
+    }
+}
+
+fn assert_str_integrity(s: &[char], beg: usize, end: usize) {
+    assert!(beg <= end);
+    assert!(end <= s.len());
+}
+
+fn trim_broken_word_left(s: &[char], beg: usize, end: usize) -> usize {
+    assert_str_integrity(s, beg, end);
+    if beg == end || beg == 0 || s[beg].is_whitespace() || s[beg - 1].is_whitespace() {
+        return beg;
+    }
+    let mut b = beg;
+    while b < end && !s[b].is_whitespace() {
+        b += 1;
+    }
+    b
+}
+
+fn trim_broken_word_right(s: &[char], beg: usize, end: usize) -> usize {
+    assert_str_integrity(s, beg, end);
+    if beg == end || end == s.len() || s[end - 1].is_whitespace() || s[end].is_whitespace() {
+        return end;
+    }
+    let mut e = end;
+    while beg < e && !s[e - 1].is_whitespace() {
+        e -= 1;
+    }
+    e
+}
+
+fn trim_idx(s: &[char], beg: usize, end: usize) -> (usize, usize) {
+    assert_str_integrity(s, beg, end);
+    let mut b = beg;
+    let mut e = end;
+    while b < e && s[b].is_whitespace() {
+        b += 1;
+    }
+    while b < e && s[e - 1].is_whitespace() {
+        e -= 1;
+    }
+    (b, e)
+}
+
+fn get_output_chunks(
+    all_before: &[char],
+    keyword: &str,
+    all_after: &[char],
+    config: &Config,
+) -> (String, String, String, String) {
+    // Chunk size logics are mostly copied from the GNU ptx source.
+    // https://github.com/MaiZure/coreutils-8.3/blob/master/src/ptx.c#L1234
+    let half_line_size = (config.line_width / 2) as usize;
+    let max_before_size = cmp::max(half_line_size as isize - config.gap_size as isize, 0) as usize;
+    let max_after_size = cmp::max(
+        half_line_size as isize
+            - (2 * config.trunc_str.len()) as isize
+            - keyword.len() as isize
+            - 1,
+        0,
+    ) as usize;
+
+    // Allocate plenty space for all the chunks.
+    let mut head = String::with_capacity(half_line_size);
+    let mut before = String::with_capacity(half_line_size);
+    let mut after = String::with_capacity(half_line_size);
+    let mut tail = String::with_capacity(half_line_size);
+
+    // the before chunk
+
+    // trim whitespace away from all_before to get the index where the before chunk should end.
+    let (_, before_end) = trim_idx(all_before, 0, all_before.len());
+
+    // the minimum possible begin index of the before_chunk is the end index minus the length.
+    let before_beg = cmp::max(before_end as isize - max_before_size as isize, 0) as usize;
+    // in case that falls in the middle of a word, trim away the word.
+    let before_beg = trim_broken_word_left(all_before, before_beg, before_end);
+
+    // trim away white space.
+    let (before_beg, before_end) = trim_idx(all_before, before_beg, before_end);
+
+    // and get the string.
+    let before_str: String = all_before[before_beg..before_end].iter().collect();
+    before.push_str(&before_str);
+    assert!(max_before_size >= before.len());
+
+    // the after chunk
+
+    // must be no longer than the minimum between the max size and the total available string.
+    let after_end = cmp::min(max_after_size, all_after.len());
+    // in case that falls in the middle of a word, trim away the word.
+    let after_end = trim_broken_word_right(all_after, 0, after_end);
+
+    // trim away white space.
+    let (_, after_end) = trim_idx(all_after, 0, after_end);
+
+    // and get the string
+    let after_str: String = all_after[0..after_end].iter().collect();
+    after.push_str(&after_str);
+    assert!(max_after_size >= after.len());
+
+    // the tail chunk
+
+    // max size of the tail chunk = max size of left half - space taken by before chunk - gap size.
+    let max_tail_size = cmp::max(
+        max_before_size as isize - before.len() as isize - config.gap_size as isize,
+        0,
+    ) as usize;
+
+    // the tail chunk takes text starting from where the after chunk ends (with whitespace trimmed).
+    let (tail_beg, _) = trim_idx(all_after, after_end, all_after.len());
+
+    // end = begin + max length
+    let tail_end = cmp::min(all_after.len(), tail_beg + max_tail_size) as usize;
+    // in case that falls in the middle of a word, trim away the word.
+    let tail_end = trim_broken_word_right(all_after, tail_beg, tail_end);
+
+    // trim away whitespace again.
+    let (tail_beg, tail_end) = trim_idx(all_after, tail_beg, tail_end);
+
+    // and get the string
+    let tail_str: String = all_after[tail_beg..tail_end].iter().collect();
+    tail.push_str(&tail_str);
+
+    // the head chunk
+
+    // max size of the head chunk = max size of right half - space taken by after chunk - gap size.
+    let max_head_size = cmp::max(
+        max_after_size as isize - after.len() as isize - config.gap_size as isize,
+        0,
+    ) as usize;
+
+    // the head chunk takes text from before the before chunk
+    let (_, head_end) = trim_idx(all_before, 0, before_beg);
+
+    // begin = end - max length
+    let head_beg = cmp::max(head_end as isize - max_head_size as isize, 0) as usize;
+    // in case that falls in the middle of a word, trim away the word.
+    let head_beg = trim_broken_word_left(all_before, head_beg, head_end);
+
+    // trim away white space again.
+    let (head_beg, head_end) = trim_idx(all_before, head_beg, head_end);
+
+    // and get the string.
+    let head_str: String = all_before[head_beg..head_end].iter().collect();
+    head.push_str(&head_str);
+
+    // put right context truncation string if needed
+    if after_end != all_after.len() && tail_beg == tail_end {
+        after.push_str(&config.trunc_str);
+    } else if after_end != all_after.len() && tail_end != all_after.len() {
+        tail.push_str(&config.trunc_str);
+    }
+
+    // put left context truncation string if needed
+    if before_beg != 0 && head_beg == head_end {
+        before = format!("{}{}", config.trunc_str, before);
+    } else if before_beg != 0 && head_beg != 0 {
+        head = format!("{}{}", config.trunc_str, head);
+    }
+
+    (tail, before, after, head)
+}
+
+fn tex_mapper(x: char) -> String {
+    match x {
+        '\\' => "\\backslash{}".to_owned(),
+        '$' | '%' | '#' | '&' | '_' => format!("\\{}", x),
+        '}' | '{' => format!("$\\{}$", x),
+        _ => x.to_string(),
+    }
+}
+
+/// Escape special characters for TeX.
+fn format_tex_field(s: &str) -> String {
+    let mapped_chunks: Vec<String> = s.chars().map(tex_mapper).collect();
+    mapped_chunks.join("")
+}
+
+fn format_tex_line(
+    config: &Config,
+    word_ref: &WordRef,
+    line: &str,
+    chars_line: &[char],
+    reference: &str,
+) -> String {
+    let mut output = String::new();
+    output.push_str(&format!("\\{} ", config.macro_name));
+    let all_before = if config.input_ref {
+        let before = &line[0..word_ref.position];
+        let before_start_trim_offset =
+            word_ref.position - before.trim_start_matches(reference).trim_start().len();
+        let before_end_index = before.len();
+        &chars_line[before_start_trim_offset..cmp::max(before_end_index, before_start_trim_offset)]
+    } else {
+        let before_chars_trim_idx = (0, word_ref.position);
+        &chars_line[before_chars_trim_idx.0..before_chars_trim_idx.1]
+    };
+    let keyword = &line[word_ref.position..word_ref.position_end];
+    let after_chars_trim_idx = (word_ref.position_end, chars_line.len());
+    let all_after = &chars_line[after_chars_trim_idx.0..after_chars_trim_idx.1];
+    let (tail, before, after, head) = get_output_chunks(all_before, keyword, all_after, config);
+    output.push_str(&format!(
+        "{5}{0}{6}{5}{1}{6}{5}{2}{6}{5}{3}{6}{5}{4}{6}",
+        format_tex_field(&tail),
+        format_tex_field(&before),
+        format_tex_field(keyword),
+        format_tex_field(&after),
+        format_tex_field(&head),
+        "{",
+        "}"
+    ));
+    if config.auto_ref || config.input_ref {
+        output.push_str(&format!("{}{}{}", "{", format_tex_field(reference), "}"));
+    }
+    output
+}
+
+fn format_roff_field(s: &str) -> String {
+    s.replace("\"", "\"\"")
+}
+
+fn format_roff_line(
+    config: &Config,
+    word_ref: &WordRef,
+    line: &str,
+    chars_line: &[char],
+    reference: &str,
+) -> String {
+    let mut output = String::new();
+    output.push_str(&format!(".{}", config.macro_name));
+    let all_before = if config.input_ref {
+        let before = &line[0..word_ref.position];
+        let before_start_trim_offset =
+            word_ref.position - before.trim_start_matches(reference).trim_start().len();
+        let before_end_index = before.len();
+        &chars_line[before_start_trim_offset..cmp::max(before_end_index, before_start_trim_offset)]
+    } else {
+        let before_chars_trim_idx = (0, word_ref.position);
+        &chars_line[before_chars_trim_idx.0..before_chars_trim_idx.1]
+    };
+    let keyword = &line[word_ref.position..word_ref.position_end];
+    let after_chars_trim_idx = (word_ref.position_end, chars_line.len());
+    let all_after = &chars_line[after_chars_trim_idx.0..after_chars_trim_idx.1];
+    let (tail, before, after, head) = get_output_chunks(all_before, keyword, all_after, config);
+    output.push_str(&format!(
+        " \"{}\" \"{}\" \"{}{}\" \"{}\"",
+        format_roff_field(&tail),
+        format_roff_field(&before),
+        format_roff_field(keyword),
+        format_roff_field(&after),
+        format_roff_field(&head)
+    ));
+    if config.auto_ref || config.input_ref {
+        output.push_str(&format!(" \"{}\"", format_roff_field(reference)));
+    }
+    output
+}
+
+fn write_traditional_output(
+    config: &Config,
+    file_map: &FileMap,
+    words: &BTreeSet<WordRef>,
+    output_filename: &str,
+) {
+    let mut writer: BufWriter<Box<dyn Write>> = BufWriter::new(if output_filename == "-" {
+        Box::new(stdout())
+    } else {
+        let file = crash_if_err!(1, File::create(output_filename));
+        Box::new(file)
+    });
+
+    let context_reg = Regex::new(&config.context_regex).unwrap();
+
+    for word_ref in words.iter() {
+        let file_map_value: &FileContent = file_map
+            .get(&(word_ref.filename))
+            .expect("Missing file in file map");
+        let FileContent {
+            ref lines,
+            ref chars_lines,
+            offset: _,
+        } = *(file_map_value);
+        let reference = get_reference(
+            config,
+            word_ref,
+            &lines[word_ref.local_line_nr],
+            &context_reg,
+        );
+        let output_line: String = match config.format {
+            OutFormat::Tex => format_tex_line(
+                config,
+                word_ref,
+                &lines[word_ref.local_line_nr],
+                &chars_lines[word_ref.local_line_nr],
+                &reference,
+            ),
+            OutFormat::Roff => format_roff_line(
+                config,
+                word_ref,
+                &lines[word_ref.local_line_nr],
+                &chars_lines[word_ref.local_line_nr],
+                &reference,
+            ),
+            OutFormat::Dumb => crash!(1, "There is no dumb format with GNU extensions disabled"),
+        };
+        crash_if_err!(1, writeln!(writer, "{}", output_line));
+    }
+}
+
+mod options {
+    pub static FILE: &str = "file";
+    pub static AUTO_REFERENCE: &str = "auto-reference";
+    pub static TRADITIONAL: &str = "traditional";
+    pub static FLAG_TRUNCATION: &str = "flag-truncation";
+    pub static MACRO_NAME: &str = "macro-name";
+    pub static FORMAT_ROFF: &str = "format=roff";
+    pub static RIGHT_SIDE_REFS: &str = "right-side-refs";
+    pub static SENTENCE_REGEXP: &str = "sentence-regexp";
+    pub static FORMAT_TEX: &str = "format=tex";
+    pub static WORD_REGEXP: &str = "word-regexp";
+    pub static BREAK_FILE: &str = "break-file";
+    pub static IGNORE_CASE: &str = "ignore-case";
+    pub static GAP_SIZE: &str = "gap-size";
+    pub static IGNORE_FILE: &str = "ignore-file";
+    pub static ONLY_FILE: &str = "only-file";
+    pub static REFERENCES: &str = "references";
+    pub static WIDTH: &str = "width";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    // let mut opts = Options::new();
+    let matches = uu_app().get_matches_from(args);
+
+    let input_files: Vec<String> = match &matches.values_of(options::FILE) {
+        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
+        None => vec!["-".to_string()],
+    };
+
+    let config = get_config(&matches);
+    let word_filter = WordFilter::new(&matches, &config);
+    let file_map = read_input(&input_files, &config);
+    let word_set = create_word_set(&config, &word_filter, &file_map);
+    let output_file = if !config.gnu_ext && matches.args.len() == 2 {
+        matches.value_of(options::FILE).unwrap_or("-").to_string()
+    } else {
+        "-".to_owned()
+    };
+    write_traditional_output(&config, &file_map, &word_set, &output_file);
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(BRIEF)
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+        .arg(
+            Arg::with_name(options::AUTO_REFERENCE)
+                .short("A")
+                .long(options::AUTO_REFERENCE)
+                .help("output automatically generated references")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::TRADITIONAL)
+                .short("G")
+                .long(options::TRADITIONAL)
+                .help("behave more like System V 'ptx'"),
+        )
+        .arg(
+            Arg::with_name(options::FLAG_TRUNCATION)
+                .short("F")
+                .long(options::FLAG_TRUNCATION)
+                .help("use STRING for flagging line truncations")
+                .value_name("STRING")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::MACRO_NAME)
+                .short("M")
+                .long(options::MACRO_NAME)
+                .help("macro name to use instead of 'xx'")
+                .value_name("STRING")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::FORMAT_ROFF)
+                .short("O")
+                .long(options::FORMAT_ROFF)
+                .help("generate output as roff directives"),
+        )
+        .arg(
+            Arg::with_name(options::RIGHT_SIDE_REFS)
+                .short("R")
+                .long(options::RIGHT_SIDE_REFS)
+                .help("put references at right, not counted in -w")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::SENTENCE_REGEXP)
+                .short("S")
+                .long(options::SENTENCE_REGEXP)
+                .help("for end of lines or end of sentences")
+                .value_name("REGEXP")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::FORMAT_TEX)
+                .short("T")
+                .long(options::FORMAT_TEX)
+                .help("generate output as TeX directives"),
+        )
+        .arg(
+            Arg::with_name(options::WORD_REGEXP)
+                .short("W")
+                .long(options::WORD_REGEXP)
+                .help("use REGEXP to match each keyword")
+                .value_name("REGEXP")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::BREAK_FILE)
+                .short("b")
+                .long(options::BREAK_FILE)
+                .help("word break characters in this FILE")
+                .value_name("FILE")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_CASE)
+                .short("f")
+                .long(options::IGNORE_CASE)
+                .help("fold lower case to upper case for sorting")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::GAP_SIZE)
+                .short("g")
+                .long(options::GAP_SIZE)
+                .help("gap size in columns between output fields")
+                .value_name("NUMBER")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_FILE)
+                .short("i")
+                .long(options::IGNORE_FILE)
+                .help("read ignore word list from FILE")
+                .value_name("FILE")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::ONLY_FILE)
+                .short("o")
+                .long(options::ONLY_FILE)
+                .help("read only word list from this FILE")
+                .value_name("FILE")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::REFERENCES)
+                .short("r")
+                .long(options::REFERENCES)
+                .help("first field of each line is a reference")
+                .value_name("FILE")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::WIDTH)
+                .short("w")
+                .long(options::WIDTH)
+                .help("output width in columns, reference excluded")
+                .value_name("NUMBER")
+                .takes_value(true),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_pwd/pwd.rs.html b/src/uu_pwd/pwd.rs.html new file mode 100644 index 000000000..f9ece5d41 --- /dev/null +++ b/src/uu_pwd/pwd.rs.html @@ -0,0 +1,173 @@ +pwd.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Derek Chiang <derekchiang93@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::env;
+use std::io;
+use std::path::{Path, PathBuf};
+
+use uucore::error::{FromIo, UResult, USimpleError};
+
+static ABOUT: &str = "Display the full filename of the current working directory.";
+static OPT_LOGICAL: &str = "logical";
+static OPT_PHYSICAL: &str = "physical";
+
+pub fn absolute_path(path: &Path) -> io::Result<PathBuf> {
+    let path_buf = path.canonicalize()?;
+
+    #[cfg(windows)]
+    let path_buf = Path::new(
+        path_buf
+            .as_path()
+            .to_string_lossy()
+            .trim_start_matches(r"\\?\"),
+    )
+    .to_path_buf();
+
+    Ok(path_buf)
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    match env::current_dir() {
+        Ok(logical_path) => {
+            if matches.is_present(OPT_LOGICAL) {
+                println!("{}", logical_path.display());
+            } else {
+                let physical_path = absolute_path(&logical_path)
+                    .map_err_context(|| "failed to get absolute path".to_string())?;
+                println!("{}", physical_path.display());
+            }
+        }
+        Err(e) => {
+            return Err(USimpleError::new(
+                1,
+                format!("failed to get current directory {}", e),
+            ))
+        }
+    };
+
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_LOGICAL)
+                .short("L")
+                .long(OPT_LOGICAL)
+                .help("use PWD from environment, even if it contains symlinks"),
+        )
+        .arg(
+            Arg::with_name(OPT_PHYSICAL)
+                .short("P")
+                .long(OPT_PHYSICAL)
+                .help("avoid all symlinks"),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_readlink/readlink.rs.html b/src/uu_readlink/readlink.rs.html new file mode 100644 index 000000000..8a843a42e --- /dev/null +++ b/src/uu_readlink/readlink.rs.html @@ -0,0 +1,391 @@ +readlink.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Haitao Li <lihaitao@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) errno
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs;
+use std::io::{stdout, Write};
+use std::path::{Path, PathBuf};
+use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
+
+const ABOUT: &str = "Print value of a symbolic link or canonical file name.";
+const OPT_CANONICALIZE: &str = "canonicalize";
+const OPT_CANONICALIZE_MISSING: &str = "canonicalize-missing";
+const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
+const OPT_NO_NEWLINE: &str = "no-newline";
+const OPT_QUIET: &str = "quiet";
+const OPT_SILENT: &str = "silent";
+const OPT_VERBOSE: &str = "verbose";
+const OPT_ZERO: &str = "zero";
+
+const ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mut no_newline = matches.is_present(OPT_NO_NEWLINE);
+    let use_zero = matches.is_present(OPT_ZERO);
+    let silent = matches.is_present(OPT_SILENT) || matches.is_present(OPT_QUIET);
+    let verbose = matches.is_present(OPT_VERBOSE);
+
+    let res_mode = if matches.is_present(OPT_CANONICALIZE)
+        || matches.is_present(OPT_CANONICALIZE_EXISTING)
+        || matches.is_present(OPT_CANONICALIZE_MISSING)
+    {
+        ResolveMode::Logical
+    } else {
+        ResolveMode::None
+    };
+
+    let can_mode = if matches.is_present(OPT_CANONICALIZE_EXISTING) {
+        MissingHandling::Existing
+    } else if matches.is_present(OPT_CANONICALIZE_MISSING) {
+        MissingHandling::Missing
+    } else {
+        MissingHandling::Normal
+    };
+
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+    if files.is_empty() {
+        crash!(
+            1,
+            "missing operand\nTry '{} --help' for more information",
+            uucore::execution_phrase()
+        );
+    }
+
+    if no_newline && files.len() > 1 && !silent {
+        eprintln!(
+            "{}: ignoring --no-newline with multiple arguments",
+            uucore::util_name()
+        );
+        no_newline = false;
+    }
+
+    for f in &files {
+        let p = PathBuf::from(f);
+        if res_mode == ResolveMode::None {
+            match fs::read_link(&p) {
+                Ok(path) => show(&path, no_newline, use_zero),
+                Err(err) => {
+                    if verbose {
+                        eprintln!(
+                            "{}: {}: errno {}",
+                            uucore::util_name(),
+                            f,
+                            err.raw_os_error().unwrap()
+                        );
+                    }
+                    return 1;
+                }
+            }
+        } else {
+            match canonicalize(&p, can_mode, res_mode) {
+                Ok(path) => show(&path, no_newline, use_zero),
+                Err(err) => {
+                    if verbose {
+                        eprintln!(
+                            "{}: {}: errno {:?}",
+                            uucore::util_name(),
+                            f,
+                            err.raw_os_error().unwrap()
+                        );
+                    }
+                    return 1;
+                }
+            }
+        }
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_CANONICALIZE)
+                .short("f")
+                .long(OPT_CANONICALIZE)
+                .help(
+                    "canonicalize by following every symlink in every component of the \
+                     given name recursively; all but the last component must exist",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_CANONICALIZE_EXISTING)
+                .short("e")
+                .long("canonicalize-existing")
+                .help(
+                    "canonicalize by following every symlink in every component of the \
+                     given name recursively, all components must exist",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_CANONICALIZE_MISSING)
+                .short("m")
+                .long(OPT_CANONICALIZE_MISSING)
+                .help(
+                    "canonicalize by following every symlink in every component of the \
+                     given name recursively, without requirements on components existence",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_NO_NEWLINE)
+                .short("n")
+                .long(OPT_NO_NEWLINE)
+                .help("do not output the trailing delimiter"),
+        )
+        .arg(
+            Arg::with_name(OPT_QUIET)
+                .short("q")
+                .long(OPT_QUIET)
+                .help("suppress most error messages"),
+        )
+        .arg(
+            Arg::with_name(OPT_SILENT)
+                .short("s")
+                .long(OPT_SILENT)
+                .help("suppress most error messages"),
+        )
+        .arg(
+            Arg::with_name(OPT_VERBOSE)
+                .short("v")
+                .long(OPT_VERBOSE)
+                .help("report error message"),
+        )
+        .arg(
+            Arg::with_name(OPT_ZERO)
+                .short("z")
+                .long(OPT_ZERO)
+                .help("separate output with NUL rather than newline"),
+        )
+        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
+}
+
+fn show(path: &Path, no_newline: bool, use_zero: bool) {
+    let path = path.to_str().unwrap();
+    if use_zero {
+        print!("{}\0", path);
+    } else if no_newline {
+        print!("{}", path);
+    } else {
+        println!("{}", path);
+    }
+    crash_if_err!(1, stdout().flush());
+}
+
+
\ No newline at end of file diff --git a/src/uu_realpath/realpath.rs.html b/src/uu_realpath/realpath.rs.html new file mode 100644 index 000000000..7d264d441 --- /dev/null +++ b/src/uu_realpath/realpath.rs.html @@ -0,0 +1,261 @@ +realpath.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) 2014 Vsevolod Velichko <torkvemada@sorokdva.net>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) retcode
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::path::{Path, PathBuf};
+use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
+
+static ABOUT: &str = "print the resolved path";
+
+static OPT_QUIET: &str = "quiet";
+static OPT_STRIP: &str = "strip";
+static OPT_ZERO: &str = "zero";
+static OPT_PHYSICAL: &str = "physical";
+static OPT_LOGICAL: &str = "logical";
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    /*  the list of files */
+
+    let paths: Vec<PathBuf> = matches
+        .values_of(ARG_FILES)
+        .unwrap()
+        .map(PathBuf::from)
+        .collect();
+
+    let strip = matches.is_present(OPT_STRIP);
+    let zero = matches.is_present(OPT_ZERO);
+    let quiet = matches.is_present(OPT_QUIET);
+    let logical = matches.is_present(OPT_LOGICAL);
+    let mut retcode = 0;
+    for path in &paths {
+        if let Err(e) = resolve_path(path, strip, zero, logical) {
+            if !quiet {
+                show_error!("{}: {}", e, path.display());
+            }
+            retcode = 1
+        };
+    }
+    retcode
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_QUIET)
+                .short("q")
+                .long(OPT_QUIET)
+                .help("Do not print warnings for invalid paths"),
+        )
+        .arg(
+            Arg::with_name(OPT_STRIP)
+                .short("s")
+                .long(OPT_STRIP)
+                .help("Only strip '.' and '..' components, but don't resolve symbolic links"),
+        )
+        .arg(
+            Arg::with_name(OPT_ZERO)
+                .short("z")
+                .long(OPT_ZERO)
+                .help("Separate output filenames with \\0 rather than newline"),
+        )
+        .arg(
+            Arg::with_name(OPT_LOGICAL)
+                .short("L")
+                .long(OPT_LOGICAL)
+                .help("resolve '..' components before symlinks"),
+        )
+        .arg(
+            Arg::with_name(OPT_PHYSICAL)
+                .short("P")
+                .long(OPT_PHYSICAL)
+                .overrides_with_all(&[OPT_STRIP, OPT_LOGICAL])
+                .help("resolve symlinks as encountered (default)"),
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .required(true)
+                .min_values(1),
+        )
+}
+
+/// Resolve a path to an absolute form and print it.
+///
+/// If `strip` is `true`, then this function does not attempt to resolve
+/// symbolic links in the path. If `zero` is `true`, then this function
+/// prints the path followed by the null byte (`'\0'`) instead of a
+/// newline character (`'\n'`).
+///
+/// # Errors
+///
+/// This function returns an error if there is a problem resolving
+/// symbolic links.
+fn resolve_path(p: &Path, strip: bool, zero: bool, logical: bool) -> std::io::Result<()> {
+    let resolve = if strip {
+        ResolveMode::None
+    } else if logical {
+        ResolveMode::Logical
+    } else {
+        ResolveMode::Physical
+    };
+    let abs = canonicalize(p, MissingHandling::Normal, resolve)?;
+    let line_ending = if zero { '\0' } else { '\n' };
+
+    print!("{}{}", abs.display(), line_ending);
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_relpath/relpath.rs.html b/src/uu_relpath/relpath.rs.html new file mode 100644 index 000000000..498fd5f3a --- /dev/null +++ b/src/uu_relpath/relpath.rs.html @@ -0,0 +1,205 @@ +relpath.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) 2014 Vsevolod Velichko <torkvemada@sorokdva.net>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) subpath absto absfrom absbase
+
+use clap::{crate_version, App, Arg};
+use std::env;
+use std::path::{Path, PathBuf};
+use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Convert TO destination to the relative path from the FROM dir.
+If FROM path is omitted, current working dir will be used.";
+
+mod options {
+    pub const DIR: &str = "DIR";
+    pub const TO: &str = "TO";
+    pub const FROM: &str = "FROM";
+}
+
+fn usage() -> String {
+    format!("{} [-d DIR] TO [FROM]", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let to = Path::new(matches.value_of(options::TO).unwrap()).to_path_buf(); // required
+    let from = match matches.value_of(options::FROM) {
+        Some(p) => Path::new(p).to_path_buf(),
+        None => env::current_dir().unwrap(),
+    };
+    let absto = canonicalize(to, MissingHandling::Normal, ResolveMode::Logical).unwrap();
+    let absfrom = canonicalize(from, MissingHandling::Normal, ResolveMode::Logical).unwrap();
+
+    if matches.is_present(options::DIR) {
+        let base = Path::new(&matches.value_of(options::DIR).unwrap()).to_path_buf();
+        let absbase = canonicalize(base, MissingHandling::Normal, ResolveMode::Logical).unwrap();
+        if !absto.as_path().starts_with(absbase.as_path())
+            || !absfrom.as_path().starts_with(absbase.as_path())
+        {
+            println!("{}", absto.display());
+            return 0;
+        }
+    }
+
+    let mut suffix_pos = 0;
+    for (f, t) in absfrom.components().zip(absto.components()) {
+        if f == t {
+            suffix_pos += 1;
+        } else {
+            break;
+        }
+    }
+
+    let mut result = PathBuf::new();
+    absfrom
+        .components()
+        .skip(suffix_pos)
+        .map(|_| result.push(".."))
+        .last();
+    absto
+        .components()
+        .skip(suffix_pos)
+        .map(|x| result.push(x.as_os_str()))
+        .last();
+
+    println!("{}", result.display());
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::DIR)
+                .short("d")
+                .takes_value(true)
+                .help("If any of FROM and TO is not subpath of DIR, output absolute path instead of relative"),
+        )
+        .arg(
+            Arg::with_name(options::TO)
+                .required(true)
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::FROM)
+                .takes_value(true),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_rm/rm.rs.html b/src/uu_rm/rm.rs.html new file mode 100644 index 000000000..d3ea97b7f --- /dev/null +++ b/src/uu_rm/rm.rs.html @@ -0,0 +1,887 @@ +rm.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (path) eacces
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use remove_dir_all::remove_dir_all;
+use std::collections::VecDeque;
+use std::fs;
+use std::io::{stderr, stdin, BufRead, Write};
+use std::ops::BitOr;
+use std::path::{Path, PathBuf};
+use walkdir::{DirEntry, WalkDir};
+
+#[derive(Eq, PartialEq, Clone, Copy)]
+enum InteractiveMode {
+    None,
+    Once,
+    Always,
+}
+
+struct Options {
+    force: bool,
+    interactive: InteractiveMode,
+    #[allow(dead_code)]
+    one_fs: bool,
+    preserve_root: bool,
+    recursive: bool,
+    dir: bool,
+    verbose: bool,
+}
+
+static ABOUT: &str = "Remove (unlink) the FILE(s)";
+static OPT_DIR: &str = "dir";
+static OPT_INTERACTIVE: &str = "interactive";
+static OPT_FORCE: &str = "force";
+static OPT_NO_PRESERVE_ROOT: &str = "no-preserve-root";
+static OPT_ONE_FILE_SYSTEM: &str = "one-file-system";
+static OPT_PRESERVE_ROOT: &str = "preserve-root";
+static OPT_PROMPT: &str = "prompt";
+static OPT_PROMPT_MORE: &str = "prompt-more";
+static OPT_RECURSIVE: &str = "recursive";
+static OPT_RECURSIVE_R: &str = "recursive_R";
+static OPT_VERBOSE: &str = "verbose";
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    String::from(
+        "By default, rm does not remove directories.  Use the --recursive (-r or -R)
+        option to remove each listed directory, too, along with all of its contents
+
+        To remove a file whose name starts with a '-', for example '-foo',
+        use one of these commands:
+        rm -- -foo
+
+        rm ./-foo
+
+        Note that if you use rm to remove a file, it might be possible to recover
+        some of its contents, given sufficient expertise and/or time.  For greater
+        assurance that the contents are truly unrecoverable, consider using shred.",
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let long_usage = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&long_usage[..])
+        .get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let force = matches.is_present(OPT_FORCE);
+
+    if files.is_empty() && !force {
+        // Still check by hand and not use clap
+        // Because "rm -f" is a thing
+        show_error!("missing an argument");
+        show_error!("for help, try '{0} --help'", uucore::execution_phrase());
+        return 1;
+    } else {
+        let options = Options {
+            force,
+            interactive: {
+                if matches.is_present(OPT_PROMPT) {
+                    InteractiveMode::Always
+                } else if matches.is_present(OPT_PROMPT_MORE) {
+                    InteractiveMode::Once
+                } else if matches.is_present(OPT_INTERACTIVE) {
+                    match matches.value_of(OPT_INTERACTIVE).unwrap() {
+                        "none" => InteractiveMode::None,
+                        "once" => InteractiveMode::Once,
+                        "always" => InteractiveMode::Always,
+                        val => crash!(1, "Invalid argument to interactive ({})", val),
+                    }
+                } else {
+                    InteractiveMode::None
+                }
+            },
+            one_fs: matches.is_present(OPT_ONE_FILE_SYSTEM),
+            preserve_root: !matches.is_present(OPT_NO_PRESERVE_ROOT),
+            recursive: matches.is_present(OPT_RECURSIVE) || matches.is_present(OPT_RECURSIVE_R),
+            dir: matches.is_present(OPT_DIR),
+            verbose: matches.is_present(OPT_VERBOSE),
+        };
+        if options.interactive == InteractiveMode::Once && (options.recursive || files.len() > 3) {
+            let msg = if options.recursive {
+                "Remove all arguments recursively? "
+            } else {
+                "Remove all arguments? "
+            };
+            if !prompt(msg) {
+                return 0;
+            }
+        }
+
+        if remove(files, options) {
+            return 1;
+        }
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+
+        .arg(
+            Arg::with_name(OPT_FORCE)
+            .short("f")
+            .long(OPT_FORCE)
+            .multiple(true)
+            .help("ignore nonexistent files and arguments, never prompt")
+        )
+        .arg(
+            Arg::with_name(OPT_PROMPT)
+            .short("i")
+            .long("prompt before every removal")
+        )
+        .arg(
+            Arg::with_name(OPT_PROMPT_MORE)
+            .short("I")
+            .help("prompt once before removing more than three files, or when removing recursively. Less intrusive than -i, while still giving some protection against most mistakes")
+        )
+        .arg(
+            Arg::with_name(OPT_INTERACTIVE)
+            .long(OPT_INTERACTIVE)
+            .help("prompt according to WHEN: never, once (-I), or always (-i). Without WHEN, prompts always")
+            .value_name("WHEN")
+            .takes_value(true)
+        )
+        .arg(
+            Arg::with_name(OPT_ONE_FILE_SYSTEM)
+            .long(OPT_ONE_FILE_SYSTEM)
+            .help("when removing a hierarchy recursively, skip any directory that is on a file system different from that of the corresponding command line argument (NOT IMPLEMENTED)")
+        )
+        .arg(
+            Arg::with_name(OPT_NO_PRESERVE_ROOT)
+            .long(OPT_NO_PRESERVE_ROOT)
+            .help("do not treat '/' specially")
+        )
+        .arg(
+            Arg::with_name(OPT_PRESERVE_ROOT)
+            .long(OPT_PRESERVE_ROOT)
+            .help("do not remove '/' (default)")
+        )
+        .arg(
+            Arg::with_name(OPT_RECURSIVE).short("r")
+            .long(OPT_RECURSIVE)
+            .help("remove directories and their contents recursively")
+        )
+        .arg(
+            // To mimic GNU's behavior we also want the '-R' flag. However, using clap's
+            // alias method 'visible_alias("R")' would result in a long '--R' flag.
+            Arg::with_name(OPT_RECURSIVE_R).short("R")
+            .help("Equivalent to -r")
+        )
+        .arg(
+            Arg::with_name(OPT_DIR)
+            .short("d")
+            .long(OPT_DIR)
+            .help("remove empty directories")
+        )
+        .arg(
+            Arg::with_name(OPT_VERBOSE)
+            .short("v")
+            .long(OPT_VERBOSE)
+            .help("explain what is being done")
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+            .multiple(true)
+            .takes_value(true)
+            .min_values(1)
+        )
+}
+
+// TODO: implement one-file-system (this may get partially implemented in walkdir)
+fn remove(files: Vec<String>, options: Options) -> bool {
+    let mut had_err = false;
+
+    for filename in &files {
+        let file = Path::new(filename);
+        had_err = match file.symlink_metadata() {
+            Ok(metadata) => {
+                if metadata.is_dir() {
+                    handle_dir(file, &options)
+                } else if is_symlink_dir(&metadata) {
+                    remove_dir(file, &options)
+                } else {
+                    remove_file(file, &options)
+                }
+            }
+            Err(_e) => {
+                // TODO: actually print out the specific error
+                // TODO: When the error is not about missing files
+                // (e.g., permission), even rm -f should fail with
+                // outputting the error, but there's no easy eay.
+                if !options.force {
+                    show_error!("cannot remove '{}': No such file or directory", filename);
+                    true
+                } else {
+                    false
+                }
+            }
+        }
+        .bitor(had_err);
+    }
+
+    had_err
+}
+
+fn handle_dir(path: &Path, options: &Options) -> bool {
+    let mut had_err = false;
+
+    let is_root = path.has_root() && path.parent().is_none();
+    if options.recursive && (!is_root || !options.preserve_root) {
+        if options.interactive != InteractiveMode::Always && !options.verbose {
+            // we need the extra crate because apparently fs::remove_dir_all() does not function
+            // correctly on Windows
+            if let Err(e) = remove_dir_all(path) {
+                had_err = true;
+                if e.kind() == std::io::ErrorKind::PermissionDenied {
+                    // GNU compatibility (rm/fail-eacces.sh)
+                    // here, GNU doesn't use some kind of remove_dir_all
+                    // It will show directory+file
+                    show_error!(
+                        "cannot remove '{}': {}",
+                        path.display(),
+                        "Permission denied"
+                    );
+                } else {
+                    show_error!("cannot remove '{}': {}", path.display(), e);
+                }
+            }
+        } else {
+            let mut dirs: VecDeque<DirEntry> = VecDeque::new();
+
+            for entry in WalkDir::new(path) {
+                match entry {
+                    Ok(entry) => {
+                        let file_type = entry.file_type();
+                        if file_type.is_dir() {
+                            dirs.push_back(entry);
+                        } else {
+                            had_err = remove_file(entry.path(), options).bitor(had_err);
+                        }
+                    }
+                    Err(e) => {
+                        had_err = true;
+                        show_error!("recursing in '{}': {}", path.display(), e);
+                    }
+                }
+            }
+
+            for dir in dirs.iter().rev() {
+                had_err = remove_dir(dir.path(), options).bitor(had_err);
+            }
+        }
+    } else if options.dir && (!is_root || !options.preserve_root) {
+        had_err = remove_dir(path, options).bitor(had_err);
+    } else if options.recursive {
+        show_error!("could not remove directory '{}'", path.display());
+        had_err = true;
+    } else {
+        show_error!(
+            "cannot remove '{}': Is a directory", // GNU's rm error message does not include help
+            path.display()
+        );
+        had_err = true;
+    }
+
+    had_err
+}
+
+fn remove_dir(path: &Path, options: &Options) -> bool {
+    let response = if options.interactive == InteractiveMode::Always {
+        prompt_file(path, true)
+    } else {
+        true
+    };
+    if response {
+        if let Ok(mut read_dir) = fs::read_dir(path) {
+            if options.dir || options.recursive {
+                if read_dir.next().is_none() {
+                    match fs::remove_dir(path) {
+                        Ok(_) => {
+                            if options.verbose {
+                                println!("removed directory '{}'", normalize(path).display());
+                            }
+                        }
+                        Err(e) => {
+                            if e.kind() == std::io::ErrorKind::PermissionDenied {
+                                // GNU compatibility (rm/fail-eacces.sh)
+                                show_error!(
+                                    "cannot remove '{}': {}",
+                                    path.display(),
+                                    "Permission denied"
+                                );
+                            } else {
+                                show_error!("cannot remove '{}': {}", path.display(), e);
+                            }
+                            return true;
+                        }
+                    }
+                } else {
+                    // directory can be read but is not empty
+                    show_error!("cannot remove '{}': Directory not empty", path.display());
+                    return true;
+                }
+            } else {
+                // called to remove a symlink_dir (windows) without "-r"/"-R" or "-d"
+                show_error!("cannot remove '{}': Is a directory", path.display());
+                return true;
+            }
+        } else {
+            // GNU's rm shows this message if directory is empty but not readable
+            show_error!("cannot remove '{}': Directory not empty", path.display());
+            return true;
+        }
+    }
+
+    false
+}
+
+fn remove_file(path: &Path, options: &Options) -> bool {
+    let response = if options.interactive == InteractiveMode::Always {
+        prompt_file(path, false)
+    } else {
+        true
+    };
+    if response {
+        match fs::remove_file(path) {
+            Ok(_) => {
+                if options.verbose {
+                    println!("removed '{}'", normalize(path).display());
+                }
+            }
+            Err(e) => {
+                if e.kind() == std::io::ErrorKind::PermissionDenied {
+                    // GNU compatibility (rm/fail-eacces.sh)
+                    show_error!(
+                        "cannot remove '{}': {}",
+                        path.display(),
+                        "Permission denied"
+                    );
+                } else {
+                    show_error!("cannot remove '{}': {}", path.display(), e);
+                }
+                return true;
+            }
+        }
+    }
+
+    false
+}
+
+fn prompt_file(path: &Path, is_dir: bool) -> bool {
+    if is_dir {
+        prompt(&(format!("rm: remove directory '{}'? ", path.display())))
+    } else {
+        prompt(&(format!("rm: remove file '{}'? ", path.display())))
+    }
+}
+
+fn normalize(path: &Path) -> PathBuf {
+    // copied from https://github.com/rust-lang/cargo/blob/2e4cfc2b7d43328b207879228a2ca7d427d188bb/src/cargo/util/paths.rs#L65-L90
+    // both projects are MIT https://github.com/rust-lang/cargo/blob/master/LICENSE-MIT
+    // for std impl progress see rfc https://github.com/rust-lang/rfcs/issues/2208
+    // TODO: replace this once that lands
+    uucore::fs::normalize_path(path)
+}
+
+fn prompt(msg: &str) -> bool {
+    let _ = stderr().write_all(msg.as_bytes());
+    let _ = stderr().flush();
+
+    let mut buf = Vec::new();
+    let stdin = stdin();
+    let mut stdin = stdin.lock();
+
+    match stdin.read_until(b'\n', &mut buf) {
+        Ok(x) if x > 0 => matches!(buf[0], b'y' | b'Y'),
+        _ => false,
+    }
+}
+
+#[cfg(not(windows))]
+fn is_symlink_dir(_metadata: &fs::Metadata) -> bool {
+    false
+}
+
+#[cfg(windows)]
+use std::os::windows::prelude::MetadataExt;
+
+#[cfg(windows)]
+fn is_symlink_dir(metadata: &fs::Metadata) -> bool {
+    use winapi::um::winnt::FILE_ATTRIBUTE_DIRECTORY;
+
+    metadata.file_type().is_symlink()
+        && ((metadata.file_attributes() & FILE_ATTRIBUTE_DIRECTORY) != 0)
+}
+
+
\ No newline at end of file diff --git a/src/uu_rmdir/rmdir.rs.html b/src/uu_rmdir/rmdir.rs.html new file mode 100644 index 000000000..13dbfc55e --- /dev/null +++ b/src/uu_rmdir/rmdir.rs.html @@ -0,0 +1,285 @@ +rmdir.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) ENOTDIR
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs;
+use std::path::Path;
+
+static ABOUT: &str = "Remove the DIRECTORY(ies), if they are empty.";
+static OPT_IGNORE_FAIL_NON_EMPTY: &str = "ignore-fail-on-non-empty";
+static OPT_PARENTS: &str = "parents";
+static OPT_VERBOSE: &str = "verbose";
+
+static ARG_DIRS: &str = "dirs";
+
+#[cfg(unix)]
+static ENOTDIR: i32 = 20;
+#[cfg(windows)]
+static ENOTDIR: i32 = 267;
+
+fn usage() -> String {
+    format!("{0} [OPTION]... DIRECTORY...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let dirs: Vec<String> = matches
+        .values_of(ARG_DIRS)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let ignore = matches.is_present(OPT_IGNORE_FAIL_NON_EMPTY);
+    let parents = matches.is_present(OPT_PARENTS);
+    let verbose = matches.is_present(OPT_VERBOSE);
+
+    match remove(dirs, ignore, parents, verbose) {
+        Ok(()) => ( /* pass */ ),
+        Err(e) => return e,
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_IGNORE_FAIL_NON_EMPTY)
+                .long(OPT_IGNORE_FAIL_NON_EMPTY)
+                .help("ignore each failure that is solely because a directory is non-empty"),
+        )
+        .arg(
+            Arg::with_name(OPT_PARENTS)
+                .short("p")
+                .long(OPT_PARENTS)
+                .help(
+                    "remove DIRECTORY and its ancestors; e.g.,
+                  'rmdir -p a/b/c' is similar to rmdir a/b/c a/b a",
+                ),
+        )
+        .arg(
+            Arg::with_name(OPT_VERBOSE)
+                .short("v")
+                .long(OPT_VERBOSE)
+                .help("output a diagnostic for every directory processed"),
+        )
+        .arg(
+            Arg::with_name(ARG_DIRS)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1)
+                .required(true),
+        )
+}
+
+fn remove(dirs: Vec<String>, ignore: bool, parents: bool, verbose: bool) -> Result<(), i32> {
+    let mut r = Ok(());
+
+    for dir in &dirs {
+        let path = Path::new(&dir[..]);
+        r = remove_dir(path, ignore, verbose).and(r);
+        if parents {
+            let mut p = path;
+            while let Some(new_p) = p.parent() {
+                p = new_p;
+                match p.as_os_str().to_str() {
+                    None => break,
+                    Some(s) => match s {
+                        "" | "." | "/" => break,
+                        _ => (),
+                    },
+                };
+                r = remove_dir(p, ignore, verbose).and(r);
+            }
+        }
+    }
+
+    r
+}
+
+fn remove_dir(path: &Path, ignore: bool, verbose: bool) -> Result<(), i32> {
+    let mut read_dir = fs::read_dir(path).map_err(|e| {
+        if e.raw_os_error() == Some(ENOTDIR) {
+            show_error!("failed to remove '{}': Not a directory", path.display());
+        } else {
+            show_error!("reading directory '{}': {}", path.display(), e);
+        }
+        1
+    })?;
+
+    let mut r = Ok(());
+
+    if read_dir.next().is_none() {
+        match fs::remove_dir(path) {
+            Err(e) => {
+                show_error!("removing directory '{}': {}", path.display(), e);
+                r = Err(1);
+            }
+            Ok(_) if verbose => println!("removing directory, '{}'", path.display()),
+            _ => (),
+        }
+    } else if !ignore {
+        show_error!("failed to remove '{}': Directory not empty", path.display());
+        r = Err(1);
+    }
+
+    r
+}
+
+
\ No newline at end of file diff --git a/src/uu_runcon/errors.rs.html b/src/uu_runcon/errors.rs.html new file mode 100644 index 000000000..41b399606 --- /dev/null +++ b/src/uu_runcon/errors.rs.html @@ -0,0 +1,151 @@ +errors.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+
+use std::ffi::OsString;
+use std::fmt::Write;
+use std::io;
+use std::str::Utf8Error;
+
+pub(crate) type Result<T> = std::result::Result<T, Error>;
+
+#[derive(thiserror::Error, Debug)]
+pub(crate) enum Error {
+    #[error("No command is specified")]
+    MissingCommand,
+
+    #[error("SELinux is not enabled")]
+    SELinuxNotEnabled,
+
+    #[error(transparent)]
+    NotUTF8(#[from] Utf8Error),
+
+    #[error(transparent)]
+    CommandLine(#[from] clap::Error),
+
+    #[error("{operation} failed")]
+    SELinux {
+        operation: &'static str,
+        source: selinux::errors::Error,
+    },
+
+    #[error("{operation} failed")]
+    Io {
+        operation: &'static str,
+        source: io::Error,
+    },
+
+    #[error("{operation} failed on '{}'", .operand1.to_string_lossy())]
+    Io1 {
+        operation: &'static str,
+        operand1: OsString,
+        source: io::Error,
+    },
+}
+
+impl Error {
+    pub(crate) fn from_io(operation: &'static str, source: io::Error) -> Self {
+        Self::Io { operation, source }
+    }
+
+    pub(crate) fn from_io1(
+        operation: &'static str,
+        operand1: impl Into<OsString>,
+        source: io::Error,
+    ) -> Self {
+        Self::Io1 {
+            operation,
+            operand1: operand1.into(),
+            source,
+        }
+    }
+
+    pub(crate) fn from_selinux(operation: &'static str, source: selinux::errors::Error) -> Self {
+        Self::SELinux { operation, source }
+    }
+}
+
+pub(crate) fn report_full_error(mut err: &dyn std::error::Error) -> String {
+    let mut desc = String::with_capacity(256);
+    write!(&mut desc, "{}", err).unwrap();
+    while let Some(source) = err.source() {
+        err = source;
+        write!(&mut desc, ": {}", err).unwrap();
+    }
+    desc.push('.');
+    desc
+}
+
+
\ No newline at end of file diff --git a/src/uu_runcon/runcon.rs.html b/src/uu_runcon/runcon.rs.html new file mode 100644 index 000000000..4e1ac040e --- /dev/null +++ b/src/uu_runcon/runcon.rs.html @@ -0,0 +1,905 @@ +runcon.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+
+// spell-checker:ignore (vars) RFILE
+
+use uucore::{show_error, show_usage_error};
+
+use clap::{App, Arg};
+use selinux::{OpaqueSecurityContext, SecurityClass, SecurityContext};
+
+use std::borrow::Cow;
+use std::ffi::{CStr, CString, OsStr, OsString};
+use std::os::raw::c_char;
+use std::os::unix::ffi::OsStrExt;
+use std::{io, ptr};
+
+mod errors;
+
+use errors::{report_full_error, Error, Result};
+
+const VERSION: &str = env!("CARGO_PKG_VERSION");
+const ABOUT: &str = "Run command with specified security context.";
+const DESCRIPTION: &str = "Run COMMAND with completely-specified CONTEXT, or with current or \
+                      transitioned security context modified by one or more of \
+                      LEVEL, ROLE, TYPE, and USER.\n\n\
+                      If none of --compute, --type, --user, --role or --range is specified, \
+                      then the first argument is used as the complete context.\n\n\
+                      Note that only carefully-chosen contexts are likely to successfully run.\n\n\
+                      With neither CONTEXT nor COMMAND are specified, \
+                      then this prints the current security context.";
+
+pub mod options {
+    pub const COMPUTE: &str = "compute";
+
+    pub const USER: &str = "user";
+    pub const ROLE: &str = "role";
+    pub const TYPE: &str = "type";
+    pub const RANGE: &str = "range";
+}
+
+// This list is NOT exhaustive. This command might perform an `execvp()` to run
+// a different program. When that happens successfully, the exit status of this
+// process will be the exit status of that program.
+mod error_exit_status {
+    pub const SUCCESS: i32 = libc::EXIT_SUCCESS;
+    pub const NOT_FOUND: i32 = 127;
+    pub const COULD_NOT_EXECUTE: i32 = 126;
+    pub const ANOTHER_ERROR: i32 = libc::EXIT_FAILURE;
+}
+
+fn get_usage() -> String {
+    format!(
+        "{0} [CONTEXT COMMAND [ARG...]]\n    \
+         {0} [-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [ARG...]",
+        uucore::execution_phrase()
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = get_usage();
+
+    let config = uu_app().usage(usage.as_ref());
+
+    let options = match parse_command_line(config, args) {
+        Ok(r) => r,
+        Err(r) => {
+            if let Error::CommandLine(ref r) = r {
+                match r.kind {
+                    clap::ErrorKind::HelpDisplayed | clap::ErrorKind::VersionDisplayed => {
+                        println!("{}", r);
+                        return error_exit_status::SUCCESS;
+                    }
+                    _ => {}
+                }
+            }
+
+            show_usage_error!("{}.\n", r);
+            return error_exit_status::ANOTHER_ERROR;
+        }
+    };
+
+    match &options.mode {
+        CommandLineMode::Print => {
+            if let Err(r) = print_current_context() {
+                show_error!("{}", report_full_error(&r));
+                return error_exit_status::ANOTHER_ERROR;
+            }
+        }
+
+        CommandLineMode::PlainContext { context, command } => {
+            let (exit_status, err) =
+                if let Err(err) = get_plain_context(context).and_then(set_next_exec_context) {
+                    (error_exit_status::ANOTHER_ERROR, err)
+                } else {
+                    // On successful execution, the following call never returns,
+                    // and this process image is replaced.
+                    execute_command(command, &options.arguments)
+                };
+
+            show_error!("{}", report_full_error(&err));
+            return exit_status;
+        }
+
+        CommandLineMode::CustomContext {
+            compute_transition_context,
+            user,
+            role,
+            the_type,
+            range,
+            command,
+        } => {
+            if let Some(command) = command {
+                let (exit_status, err) = if let Err(err) = get_custom_context(
+                    *compute_transition_context,
+                    user.as_deref(),
+                    role.as_deref(),
+                    the_type.as_deref(),
+                    range.as_deref(),
+                    command,
+                )
+                .and_then(set_next_exec_context)
+                {
+                    (error_exit_status::ANOTHER_ERROR, err)
+                } else {
+                    // On successful execution, the following call never returns,
+                    // and this process image is replaced.
+                    execute_command(command, &options.arguments)
+                };
+
+                show_error!("{}", report_full_error(&err));
+                return exit_status;
+            } else if let Err(r) = print_current_context() {
+                show_error!("{}", report_full_error(&r));
+                return error_exit_status::ANOTHER_ERROR;
+            }
+        }
+    }
+
+    error_exit_status::SUCCESS
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(VERSION)
+        .about(ABOUT)
+        .after_help(DESCRIPTION)
+        .arg(
+            Arg::with_name(options::COMPUTE)
+                .short("c")
+                .long(options::COMPUTE)
+                .takes_value(false)
+                .help("Compute process transition context before modifying."),
+        )
+        .arg(
+            Arg::with_name(options::USER)
+                .short("u")
+                .long(options::USER)
+                .takes_value(true)
+                .value_name("USER")
+                .help("Set user USER in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::ROLE)
+                .short("r")
+                .long(options::ROLE)
+                .takes_value(true)
+                .value_name("ROLE")
+                .help("Set role ROLE in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::TYPE)
+                .short("t")
+                .long(options::TYPE)
+                .takes_value(true)
+                .value_name("TYPE")
+                .help("Set type TYPE in the target security context."),
+        )
+        .arg(
+            Arg::with_name(options::RANGE)
+                .short("l")
+                .long(options::RANGE)
+                .takes_value(true)
+                .value_name("RANGE")
+                .help("Set range RANGE in the target security context."),
+        )
+        .arg(Arg::with_name("ARG").multiple(true))
+        // Once "ARG" is parsed, everything after that belongs to it.
+        //
+        // This is not how POSIX does things, but this is how the GNU implementation
+        // parses its command line.
+        .setting(clap::AppSettings::TrailingVarArg)
+}
+
+#[derive(Debug)]
+enum CommandLineMode {
+    Print,
+
+    PlainContext {
+        context: OsString,
+        command: OsString,
+    },
+
+    CustomContext {
+        /// Compute process transition context before modifying.
+        compute_transition_context: bool,
+
+        /// Use the current context with the specified user.
+        user: Option<OsString>,
+
+        /// Use the current context with the specified role.
+        role: Option<OsString>,
+
+        /// Use the current context with the specified type.
+        the_type: Option<OsString>,
+
+        /// Use the current context with the specified range.
+        range: Option<OsString>,
+
+        // `command` can be `None`, in which case we're dealing with this syntax:
+        // runcon [-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE]
+        //
+        // This syntax is undocumented, but it is accepted by the GNU implementation,
+        // so we do the same for compatibility.
+        command: Option<OsString>,
+    },
+}
+
+#[derive(Debug)]
+struct Options {
+    mode: CommandLineMode,
+    arguments: Vec<OsString>,
+}
+
+fn parse_command_line(config: App, args: impl uucore::Args) -> Result<Options> {
+    let matches = config.get_matches_from_safe(args)?;
+
+    let compute_transition_context = matches.is_present(options::COMPUTE);
+
+    let mut args = matches
+        .values_of_os("ARG")
+        .unwrap_or_default()
+        .map(OsString::from);
+
+    if compute_transition_context
+        || matches.is_present(options::USER)
+        || matches.is_present(options::ROLE)
+        || matches.is_present(options::TYPE)
+        || matches.is_present(options::RANGE)
+    {
+        // runcon [-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] [COMMAND [args]]
+
+        let mode = CommandLineMode::CustomContext {
+            compute_transition_context,
+            user: matches.value_of_os(options::USER).map(Into::into),
+            role: matches.value_of_os(options::ROLE).map(Into::into),
+            the_type: matches.value_of_os(options::TYPE).map(Into::into),
+            range: matches.value_of_os(options::RANGE).map(Into::into),
+            command: args.next(),
+        };
+
+        Ok(Options {
+            mode,
+            arguments: args.collect(),
+        })
+    } else if let Some(context) = args.next() {
+        // runcon CONTEXT COMMAND [args]
+
+        args.next()
+            .ok_or(Error::MissingCommand)
+            .map(move |command| Options {
+                mode: CommandLineMode::PlainContext { context, command },
+                arguments: args.collect(),
+            })
+    } else {
+        // runcon
+
+        Ok(Options {
+            mode: CommandLineMode::Print,
+            arguments: Vec::default(),
+        })
+    }
+}
+
+fn print_current_context() -> Result<()> {
+    let op = "Getting security context of the current process";
+    let context = SecurityContext::current(false).map_err(|r| Error::from_selinux(op, r))?;
+
+    let context = context
+        .to_c_string()
+        .map_err(|r| Error::from_selinux(op, r))?;
+
+    if let Some(context) = context {
+        let context = context.as_ref().to_str()?;
+        println!("{}", context);
+    } else {
+        println!();
+    }
+    Ok(())
+}
+
+fn set_next_exec_context(context: OpaqueSecurityContext) -> Result<()> {
+    let c_context = context
+        .to_c_string()
+        .map_err(|r| Error::from_selinux("Creating new context", r))?;
+
+    let sc = SecurityContext::from_c_str(&c_context, false);
+
+    if sc.check() != Some(true) {
+        let ctx = OsStr::from_bytes(c_context.as_bytes());
+        let err = io::ErrorKind::InvalidInput.into();
+        return Err(Error::from_io1("Checking security context", ctx, err));
+    }
+
+    sc.set_for_next_exec()
+        .map_err(|r| Error::from_selinux("Setting new security context", r))
+}
+
+fn get_plain_context(context: &OsStr) -> Result<OpaqueSecurityContext> {
+    if selinux::kernel_support() == selinux::KernelSupport::Unsupported {
+        return Err(Error::SELinuxNotEnabled);
+    }
+
+    let c_context = os_str_to_c_string(context)?;
+
+    OpaqueSecurityContext::from_c_str(&c_context)
+        .map_err(|r| Error::from_selinux("Creating new context", r))
+}
+
+fn get_transition_context(command: &OsStr) -> Result<SecurityContext> {
+    // Generate context based on process transition.
+    let sec_class = SecurityClass::from_name("process")
+        .map_err(|r| Error::from_selinux("Getting process security class", r))?;
+
+    // Get context of file to be executed.
+    let file_context = match SecurityContext::of_path(command, true, false) {
+        Ok(Some(context)) => context,
+
+        Ok(None) => {
+            let err = io::Error::from_raw_os_error(libc::ENODATA);
+            return Err(Error::from_io1("getfilecon", command, err));
+        }
+
+        Err(r) => {
+            let op = "Getting security context of command file";
+            return Err(Error::from_selinux(op, r));
+        }
+    };
+
+    let process_context = SecurityContext::current(false)
+        .map_err(|r| Error::from_selinux("Getting security context of the current process", r))?;
+
+    // Compute result of process transition.
+    process_context
+        .of_labeling_decision(&file_context, sec_class, "")
+        .map_err(|r| Error::from_selinux("Computing result of process transition", r))
+}
+
+fn get_initial_custom_opaque_context(
+    compute_transition_context: bool,
+    command: &OsStr,
+) -> Result<OpaqueSecurityContext> {
+    let context = if compute_transition_context {
+        get_transition_context(command)?
+    } else {
+        SecurityContext::current(false).map_err(|r| {
+            Error::from_selinux("Getting security context of the current process", r)
+        })?
+    };
+
+    let c_context = context
+        .to_c_string()
+        .map_err(|r| Error::from_selinux("Getting security context", r))?
+        .unwrap_or_else(|| Cow::Owned(CString::default()));
+
+    OpaqueSecurityContext::from_c_str(c_context.as_ref())
+        .map_err(|r| Error::from_selinux("Creating new context", r))
+}
+
+fn get_custom_context(
+    compute_transition_context: bool,
+    user: Option<&OsStr>,
+    role: Option<&OsStr>,
+    the_type: Option<&OsStr>,
+    range: Option<&OsStr>,
+    command: &OsStr,
+) -> Result<OpaqueSecurityContext> {
+    use OpaqueSecurityContext as OSC;
+    type SetNewValueProc = fn(&OSC, &CStr) -> selinux::errors::Result<()>;
+
+    if selinux::kernel_support() == selinux::KernelSupport::Unsupported {
+        return Err(Error::SELinuxNotEnabled);
+    }
+
+    let osc = get_initial_custom_opaque_context(compute_transition_context, command)?;
+
+    let list: &[(Option<&OsStr>, SetNewValueProc, &'static str)] = &[
+        (user, OSC::set_user, "Setting security context user"),
+        (role, OSC::set_role, "Setting security context role"),
+        (the_type, OSC::set_type, "Setting security context type"),
+        (range, OSC::set_range, "Setting security context range"),
+    ];
+
+    for &(new_value, method, op) in list {
+        if let Some(new_value) = new_value {
+            let c_new_value = os_str_to_c_string(new_value)?;
+            method(&osc, &c_new_value).map_err(|r| Error::from_selinux(op, r))?;
+        }
+    }
+    Ok(osc)
+}
+
+/// The actual return type of this function should be `Result<!, (i32, Error)>`
+/// However, until the *never* type is stabilized, one way to indicate to the
+/// compiler the only valid return type is to say "if this returns, it will
+/// always return an error".
+fn execute_command(command: &OsStr, arguments: &[OsString]) -> (i32, Error) {
+    let c_command = match os_str_to_c_string(command) {
+        Ok(v) => v,
+        Err(r) => return (error_exit_status::ANOTHER_ERROR, r),
+    };
+
+    let argv_storage: Vec<CString> = match arguments
+        .iter()
+        .map(AsRef::as_ref)
+        .map(os_str_to_c_string)
+        .collect::<Result<_>>()
+    {
+        Ok(v) => v,
+        Err(r) => return (error_exit_status::ANOTHER_ERROR, r),
+    };
+
+    let mut argv: Vec<*const c_char> = Vec::with_capacity(arguments.len().saturating_add(2));
+    argv.push(c_command.as_ptr());
+    argv.extend(argv_storage.iter().map(AsRef::as_ref).map(CStr::as_ptr));
+    argv.push(ptr::null());
+
+    unsafe { libc::execvp(c_command.as_ptr(), argv.as_ptr()) };
+
+    let err = io::Error::last_os_error();
+    let exit_status = if err.kind() == io::ErrorKind::NotFound {
+        error_exit_status::NOT_FOUND
+    } else {
+        error_exit_status::COULD_NOT_EXECUTE
+    };
+
+    let err = Error::from_io1("Executing command", command, err);
+    (exit_status, err)
+}
+
+fn os_str_to_c_string(s: &OsStr) -> Result<CString> {
+    CString::new(s.as_bytes())
+        .map_err(|_r| Error::from_io("CString::new()", io::ErrorKind::InvalidInput.into()))
+}
+
+
\ No newline at end of file diff --git a/src/uu_seq/seq.rs.html b/src/uu_seq/seq.rs.html new file mode 100644 index 000000000..f9f610a91 --- /dev/null +++ b/src/uu_seq/seq.rs.html @@ -0,0 +1,553 @@ +seq.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+
+// TODO: Make -w flag work with decimals
+// TODO: Support -f flag
+
+// spell-checker:ignore (ToDO) istr chiter argptr ilen
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, AppSettings, Arg};
+use num_bigint::BigInt;
+use num_traits::One;
+use num_traits::Zero;
+use num_traits::{Num, ToPrimitive};
+use std::cmp;
+use std::io::{stdout, Write};
+use std::str::FromStr;
+
+static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
+static OPT_SEPARATOR: &str = "separator";
+static OPT_TERMINATOR: &str = "terminator";
+static OPT_WIDTHS: &str = "widths";
+
+static ARG_NUMBERS: &str = "numbers";
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... LAST
+    {0} [OPTION]... FIRST LAST
+    {0} [OPTION]... FIRST INCREMENT LAST",
+        uucore::execution_phrase()
+    )
+}
+#[derive(Clone)]
+struct SeqOptions {
+    separator: String,
+    terminator: String,
+    widths: bool,
+}
+
+enum Number {
+    BigInt(BigInt),
+    F64(f64),
+}
+
+impl Number {
+    fn is_zero(&self) -> bool {
+        match self {
+            Number::BigInt(n) => n.is_zero(),
+            Number::F64(n) => n.is_zero(),
+        }
+    }
+
+    fn into_f64(self) -> f64 {
+        match self {
+            // BigInt::to_f64() can not return None.
+            Number::BigInt(n) => n.to_f64().unwrap(),
+            Number::F64(n) => n,
+        }
+    }
+}
+
+impl FromStr for Number {
+    type Err = String;
+    fn from_str(mut s: &str) -> Result<Self, Self::Err> {
+        if s.starts_with('+') {
+            s = &s[1..];
+        }
+
+        match s.parse::<BigInt>() {
+            Ok(n) => Ok(Number::BigInt(n)),
+            Err(_) => match s.parse::<f64>() {
+                Ok(value) if value.is_nan() => Err(format!(
+                    "invalid 'not-a-number' argument: '{}'\nTry '{} --help' for more information.",
+                    s,
+                    uucore::execution_phrase(),
+                )),
+                Ok(value) => Ok(Number::F64(value)),
+                Err(_) => Err(format!(
+                    "invalid floating point argument: '{}'\nTry '{} --help' for more information.",
+                    s,
+                    uucore::execution_phrase(),
+                )),
+            },
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let numbers = matches.values_of(ARG_NUMBERS).unwrap().collect::<Vec<_>>();
+
+    let options = SeqOptions {
+        separator: matches.value_of(OPT_SEPARATOR).unwrap_or("\n").to_string(),
+        terminator: matches.value_of(OPT_TERMINATOR).unwrap_or("\n").to_string(),
+        widths: matches.is_present(OPT_WIDTHS),
+    };
+
+    let mut largest_dec = 0;
+    let mut padding = 0;
+    let first = if numbers.len() > 1 {
+        let slice = numbers[0];
+        let len = slice.len();
+        let dec = slice.find('.').unwrap_or(len);
+        largest_dec = len - dec;
+        padding = dec;
+        return_if_err!(1, slice.parse())
+    } else {
+        Number::BigInt(BigInt::one())
+    };
+    let increment = if numbers.len() > 2 {
+        let slice = numbers[1];
+        let len = slice.len();
+        let dec = slice.find('.').unwrap_or(len);
+        largest_dec = cmp::max(largest_dec, len - dec);
+        padding = cmp::max(padding, dec);
+        return_if_err!(1, slice.parse())
+    } else {
+        Number::BigInt(BigInt::one())
+    };
+    if increment.is_zero() {
+        show_error!(
+            "invalid Zero increment value: '{}'\nTry '{} --help' for more information.",
+            numbers[1],
+            uucore::execution_phrase()
+        );
+        return 1;
+    }
+    let last = {
+        let slice = numbers[numbers.len() - 1];
+        padding = cmp::max(padding, slice.find('.').unwrap_or_else(|| slice.len()));
+        return_if_err!(1, slice.parse())
+    };
+    if largest_dec > 0 {
+        largest_dec -= 1;
+    }
+
+    match (first, last, increment) {
+        (Number::BigInt(first), Number::BigInt(last), Number::BigInt(increment)) => {
+            print_seq_integers(
+                first,
+                increment,
+                last,
+                options.separator,
+                options.terminator,
+                options.widths,
+                padding,
+            )
+        }
+        (first, last, increment) => print_seq(
+            first.into_f64(),
+            increment.into_f64(),
+            last.into_f64(),
+            largest_dec,
+            options.separator,
+            options.terminator,
+            options.widths,
+            padding,
+        ),
+    }
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .setting(AppSettings::AllowLeadingHyphen)
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(OPT_SEPARATOR)
+                .short("s")
+                .long("separator")
+                .help("Separator character (defaults to \\n)")
+                .takes_value(true)
+                .number_of_values(1),
+        )
+        .arg(
+            Arg::with_name(OPT_TERMINATOR)
+                .short("t")
+                .long("terminator")
+                .help("Terminator character (defaults to \\n)")
+                .takes_value(true)
+                .number_of_values(1),
+        )
+        .arg(
+            Arg::with_name(OPT_WIDTHS)
+                .short("w")
+                .long("widths")
+                .help("Equalize widths of all numbers by padding with zeros"),
+        )
+        .arg(
+            Arg::with_name(ARG_NUMBERS)
+                .multiple(true)
+                .takes_value(true)
+                .allow_hyphen_values(true)
+                .max_values(3)
+                .required(true),
+        )
+}
+
+fn done_printing<T: Num + PartialOrd>(next: &T, increment: &T, last: &T) -> bool {
+    if increment >= &T::zero() {
+        next > last
+    } else {
+        next < last
+    }
+}
+
+/// Floating point based code path
+#[allow(clippy::too_many_arguments)]
+fn print_seq(
+    first: f64,
+    increment: f64,
+    last: f64,
+    largest_dec: usize,
+    separator: String,
+    terminator: String,
+    pad: bool,
+    padding: usize,
+) {
+    let mut i = 0isize;
+    let mut value = first + i as f64 * increment;
+    while !done_printing(&value, &increment, &last) {
+        let istr = format!("{:.*}", largest_dec, value);
+        let ilen = istr.len();
+        let before_dec = istr.find('.').unwrap_or(ilen);
+        if pad && before_dec < padding {
+            for _ in 0..(padding - before_dec) {
+                print!("0");
+            }
+        }
+        print!("{}", istr);
+        i += 1;
+        value = first + i as f64 * increment;
+        if !done_printing(&value, &increment, &last) {
+            print!("{}", separator);
+        }
+    }
+    if (first >= last && increment < 0f64) || (first <= last && increment > 0f64) {
+        print!("{}", terminator);
+    }
+    crash_if_err!(1, stdout().flush());
+}
+
+/// BigInt based code path
+fn print_seq_integers(
+    first: BigInt,
+    increment: BigInt,
+    last: BigInt,
+    separator: String,
+    terminator: String,
+    pad: bool,
+    padding: usize,
+) {
+    let mut value = first;
+    let mut is_first_iteration = true;
+    while !done_printing(&value, &increment, &last) {
+        if !is_first_iteration {
+            print!("{}", separator);
+        }
+        is_first_iteration = false;
+        if pad {
+            print!("{number:>0width$}", number = value, width = padding);
+        } else {
+            print!("{}", value);
+        }
+        value += &increment;
+    }
+
+    if !is_first_iteration {
+        print!("{}", terminator);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_shred/shred.rs.html b/src/uu_shred/shred.rs.html new file mode 100644 index 000000000..65e6c1c96 --- /dev/null +++ b/src/uu_shred/shred.rs.html @@ -0,0 +1,1351 @@ +shred.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) Michael Rosenberg <42micro@gmail.com>
+// * (c) Fort <forticulous@gmail.com>
+// *
+// * For the full copyright and license information, please view the LICENSE
+// * file that was distributed with this source code.
+
+// spell-checker:ignore (words) writeback wipesync
+
+use clap::{crate_version, App, Arg};
+use rand::prelude::SliceRandom;
+use rand::Rng;
+use std::cell::{Cell, RefCell};
+use std::fs;
+use std::fs::{File, OpenOptions};
+use std::io;
+use std::io::prelude::*;
+use std::io::SeekFrom;
+use std::path::{Path, PathBuf};
+use uucore::InvalidEncodingHandling;
+
+#[macro_use]
+extern crate uucore;
+
+static NAME: &str = "shred";
+const BLOCK_SIZE: usize = 512;
+const NAME_CHARSET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.";
+
+// Patterns as shown in the GNU coreutils shred implementation
+const PATTERNS: [&[u8]; 22] = [
+    b"\x00",
+    b"\xFF",
+    b"\x55",
+    b"\xAA",
+    b"\x24\x92\x49",
+    b"\x49\x24\x92",
+    b"\x6D\xB6\xDB",
+    b"\x92\x49\x24",
+    b"\xB6\xDB\x6D",
+    b"\xDB\x6D\xB6",
+    b"\x11",
+    b"\x22",
+    b"\x33",
+    b"\x44",
+    b"\x66",
+    b"\x77",
+    b"\x88",
+    b"\x99",
+    b"\xBB",
+    b"\xCC",
+    b"\xDD",
+    b"\xEE",
+];
+
+#[derive(Clone, Copy)]
+enum PassType<'a> {
+    Pattern(&'a [u8]),
+    Random,
+}
+
+// Used to generate all possible filenames of a certain length using NAME_CHARSET as an alphabet
+struct FilenameGenerator {
+    name_len: usize,
+    name_charset_indices: RefCell<Vec<usize>>, // Store the indices of the letters of our filename in NAME_CHARSET
+    exhausted: Cell<bool>,
+}
+
+impl FilenameGenerator {
+    fn new(name_len: usize) -> FilenameGenerator {
+        let indices: Vec<usize> = vec![0; name_len];
+        FilenameGenerator {
+            name_len,
+            name_charset_indices: RefCell::new(indices),
+            exhausted: Cell::new(false),
+        }
+    }
+}
+
+impl Iterator for FilenameGenerator {
+    type Item = String;
+
+    fn next(&mut self) -> Option<String> {
+        if self.exhausted.get() {
+            return None;
+        }
+
+        let mut name_charset_indices = self.name_charset_indices.borrow_mut();
+
+        // Make the return value, then increment
+        let mut ret = String::new();
+        for i in name_charset_indices.iter() {
+            let c = char::from(NAME_CHARSET[*i]);
+            ret.push(c);
+        }
+
+        if name_charset_indices[0] == NAME_CHARSET.len() - 1 {
+            self.exhausted.set(true)
+        }
+        // Now increment the least significant index
+        for i in (0..self.name_len).rev() {
+            if name_charset_indices[i] == NAME_CHARSET.len() - 1 {
+                name_charset_indices[i] = 0; // Carry the 1
+                continue;
+            } else {
+                name_charset_indices[i] += 1;
+                break;
+            }
+        }
+
+        Some(ret)
+    }
+}
+
+// Used to generate blocks of bytes of size <= BLOCK_SIZE based on either a give pattern
+// or randomness
+struct BytesGenerator<'a> {
+    total_bytes: u64,
+    bytes_generated: Cell<u64>,
+    block_size: usize,
+    exact: bool, // if false, every block's size is block_size
+    gen_type: PassType<'a>,
+    rng: Option<RefCell<rand::rngs::ThreadRng>>,
+    bytes: [u8; BLOCK_SIZE],
+}
+
+impl<'a> BytesGenerator<'a> {
+    fn new(total_bytes: u64, gen_type: PassType<'a>, exact: bool) -> BytesGenerator {
+        let rng = match gen_type {
+            PassType::Random => Some(RefCell::new(rand::thread_rng())),
+            _ => None,
+        };
+
+        let bytes = [0; BLOCK_SIZE];
+
+        BytesGenerator {
+            total_bytes,
+            bytes_generated: Cell::new(0u64),
+            block_size: BLOCK_SIZE,
+            exact,
+            gen_type,
+            rng,
+            bytes,
+        }
+    }
+
+    pub fn reset(&mut self, total_bytes: u64, gen_type: PassType<'a>) {
+        if let PassType::Random = gen_type {
+            if self.rng.is_none() {
+                self.rng = Some(RefCell::new(rand::thread_rng()));
+            }
+        }
+
+        self.total_bytes = total_bytes;
+        self.gen_type = gen_type;
+
+        self.bytes_generated.set(0);
+    }
+
+    pub fn next(&mut self) -> Option<&[u8]> {
+        // We go over the total_bytes limit when !self.exact and total_bytes isn't a multiple
+        // of self.block_size
+        if self.bytes_generated.get() >= self.total_bytes {
+            return None;
+        }
+
+        let this_block_size = if !self.exact {
+            self.block_size
+        } else {
+            let bytes_left = self.total_bytes - self.bytes_generated.get();
+            if bytes_left >= self.block_size as u64 {
+                self.block_size
+            } else {
+                (bytes_left % self.block_size as u64) as usize
+            }
+        };
+
+        let bytes = &mut self.bytes[..this_block_size];
+
+        match self.gen_type {
+            PassType::Random => {
+                let mut rng = self.rng.as_ref().unwrap().borrow_mut();
+                rng.fill(bytes);
+            }
+            PassType::Pattern(pattern) => {
+                let skip = if self.bytes_generated.get() == 0 {
+                    0
+                } else {
+                    (pattern.len() as u64 % self.bytes_generated.get()) as usize
+                };
+
+                // Copy the pattern in chunks rather than simply one byte at a time
+                let mut i = 0;
+                while i < this_block_size {
+                    let start = (i + skip) % pattern.len();
+                    let end = (this_block_size - i).min(pattern.len());
+                    let len = end - start;
+
+                    bytes[i..i + len].copy_from_slice(&pattern[start..end]);
+
+                    i += len;
+                }
+            }
+        };
+
+        let new_bytes_generated = self.bytes_generated.get() + this_block_size as u64;
+        self.bytes_generated.set(new_bytes_generated);
+
+        Some(bytes)
+    }
+}
+
+static ABOUT: &str = "Overwrite the specified FILE(s) repeatedly, in order to make it harder\n\
+for even very expensive hardware probing to recover the data.
+";
+
+fn usage() -> String {
+    format!("{} [OPTION]... FILE...", uucore::execution_phrase())
+}
+
+static AFTER_HELP: &str =
+    "Delete FILE(s) if --remove (-u) is specified.  The default is not to remove\n\
+     the files because it is common to operate on device files like /dev/hda,\n\
+     and those files usually should not be removed.\n\
+     \n\
+     CAUTION: Note that shred relies on a very important assumption:\n\
+     that the file system overwrites data in place.  This is the traditional\n\
+     way to do things, but many modern file system designs do not satisfy this\n\
+     assumption.  The following are examples of file systems on which shred is\n\
+     not effective, or is not guaranteed to be effective in all file system modes:\n\
+     \n\
+     * log-structured or journal file systems, such as those supplied with\n\
+     AIX and Solaris (and JFS, ReiserFS, XFS, Ext3, etc.)\n\
+     \n\
+     * file systems that write redundant data and carry on even if some writes\n\
+     fail, such as RAID-based file systems\n\
+     \n\
+     * file systems that make snapshots, such as Network Appliance's NFS server\n\
+     \n\
+     * file systems that cache in temporary locations, such as NFS\n\
+     version 3 clients\n\
+     \n\
+     * compressed file systems\n\
+     \n\
+     In the case of ext3 file systems, the above disclaimer applies\n\
+     and shred is thus of limited effectiveness) only in data=journal mode,\n\
+     which journals file data in addition to just metadata.  In both the\n\
+     data=ordered (default) and data=writeback modes, shred works as usual.\n\
+     Ext3 journal modes can be changed by adding the data=something option\n\
+     to the mount options for a particular file system in the /etc/fstab file,\n\
+     as documented in the mount man page (man mount).\n\
+     \n\
+     In addition, file system backups and remote mirrors may contain copies\n\
+     of the file that cannot be removed, and that will allow a shredded file\n\
+     to be recovered later.\n\
+     ";
+
+pub mod options {
+    pub const FORCE: &str = "force";
+    pub const FILE: &str = "file";
+    pub const ITERATIONS: &str = "iterations";
+    pub const SIZE: &str = "size";
+    pub const REMOVE: &str = "remove";
+    pub const VERBOSE: &str = "verbose";
+    pub const EXACT: &str = "exact";
+    pub const ZERO: &str = "zero";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+
+    let app = uu_app().usage(&usage[..]);
+
+    let matches = app.get_matches_from(args);
+
+    let mut errs: Vec<String> = vec![];
+
+    if !matches.is_present(options::FILE) {
+        show_error!("Missing an argument");
+        show_error!("For help, try '{} --help'", NAME);
+        return 0;
+    }
+
+    let iterations = match matches.value_of(options::ITERATIONS) {
+        Some(s) => match s.parse::<usize>() {
+            Ok(u) => u,
+            Err(_) => {
+                errs.push(format!("invalid number of passes: '{}'", s));
+                0
+            }
+        },
+        None => unreachable!(),
+    };
+
+    // TODO: implement --remove HOW
+    //       The optional HOW parameter indicates how to remove a directory entry:
+    //         - 'unlink' => use a standard unlink call.
+    //         - 'wipe' => also first obfuscate bytes in the name.
+    //         - 'wipesync' => also sync each obfuscated byte to disk.
+    //       The default mode is 'wipesync', but note it can be expensive.
+
+    // TODO: implement --random-source
+
+    let force = matches.is_present(options::FORCE);
+    let remove = matches.is_present(options::REMOVE);
+    let size_arg = matches.value_of(options::SIZE).map(|s| s.to_string());
+    let size = get_size(size_arg);
+    let exact = matches.is_present(options::EXACT) && size.is_none(); // if -s is given, ignore -x
+    let zero = matches.is_present(options::ZERO);
+    let verbose = matches.is_present(options::VERBOSE);
+
+    if !errs.is_empty() {
+        show_error!("Invalid arguments supplied.");
+        for message in errs {
+            show_error!("{}", message);
+        }
+        return 1;
+    }
+
+    for path_str in matches.values_of(options::FILE).unwrap() {
+        wipe_file(
+            path_str, iterations, remove, size, exact, zero, verbose, force,
+        );
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(AFTER_HELP)
+        .arg(
+            Arg::with_name(options::FORCE)
+                .long(options::FORCE)
+                .short("f")
+                .help("change permissions to allow writing if necessary"),
+        )
+        .arg(
+            Arg::with_name(options::ITERATIONS)
+                .long(options::ITERATIONS)
+                .short("n")
+                .help("overwrite N times instead of the default (3)")
+                .value_name("NUMBER")
+                .default_value("3"),
+        )
+        .arg(
+            Arg::with_name(options::SIZE)
+                .long(options::SIZE)
+                .short("s")
+                .takes_value(true)
+                .value_name("N")
+                .help("shred this many bytes (suffixes like K, M, G accepted)"),
+        )
+        .arg(
+            Arg::with_name(options::REMOVE)
+                .short("u")
+                .long(options::REMOVE)
+                .help("truncate and remove file after overwriting;  See below"),
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE)
+                .long(options::VERBOSE)
+                .short("v")
+                .help("show progress"),
+        )
+        .arg(
+            Arg::with_name(options::EXACT)
+                .long(options::EXACT)
+                .short("x")
+                .help(
+                    "do not round file sizes up to the next full block;\n\
+                     this is the default for non-regular files",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::ZERO)
+                .long(options::ZERO)
+                .short("z")
+                .help("add a final overwrite with zeros to hide shredding"),
+        )
+        // Positional arguments
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+}
+
+// TODO: Add support for all postfixes here up to and including EiB
+//       http://www.gnu.org/software/coreutils/manual/coreutils.html#Block-size
+fn get_size(size_str_opt: Option<String>) -> Option<u64> {
+    size_str_opt.as_ref()?;
+
+    let mut size_str = size_str_opt.as_ref().unwrap().clone();
+    // Immutably look at last character of size string
+    let unit = match size_str.chars().last().unwrap() {
+        'K' => {
+            size_str.pop();
+            1024u64
+        }
+        'M' => {
+            size_str.pop();
+            (1024 * 1024) as u64
+        }
+        'G' => {
+            size_str.pop();
+            (1024 * 1024 * 1024) as u64
+        }
+        _ => 1u64,
+    };
+
+    let coefficient = match size_str.parse::<u64>() {
+        Ok(u) => u,
+        Err(_) => {
+            println!("{}: {}: Invalid file size", NAME, size_str_opt.unwrap());
+            exit!(1);
+        }
+    };
+
+    Some(coefficient * unit)
+}
+
+fn pass_name(pass_type: PassType) -> String {
+    match pass_type {
+        PassType::Random => String::from("random"),
+        PassType::Pattern(bytes) => {
+            let mut s: String = String::new();
+            while s.len() < 6 {
+                for b in bytes {
+                    let readable: String = format!("{:x}", b);
+                    s.push_str(&readable);
+                }
+            }
+            s
+        }
+    }
+}
+
+#[allow(clippy::too_many_arguments)]
+fn wipe_file(
+    path_str: &str,
+    n_passes: usize,
+    remove: bool,
+    size: Option<u64>,
+    exact: bool,
+    zero: bool,
+    verbose: bool,
+    force: bool,
+) {
+    // Get these potential errors out of the way first
+    let path: &Path = Path::new(path_str);
+    if !path.exists() {
+        show_error!("{}: No such file or directory", path.display());
+        return;
+    }
+    if !path.is_file() {
+        show_error!("{}: Not a file", path.display());
+        return;
+    }
+
+    // If force is true, set file permissions to not-readonly.
+    if force {
+        let metadata = match fs::metadata(path) {
+            Ok(m) => m,
+            Err(e) => {
+                show_error!("{}", e);
+                return;
+            }
+        };
+
+        let mut perms = metadata.permissions();
+        perms.set_readonly(false);
+        if let Err(e) = fs::set_permissions(path, perms) {
+            show_error!("{}", e);
+            return;
+        }
+    }
+
+    // Fill up our pass sequence
+    let mut pass_sequence: Vec<PassType> = Vec::new();
+
+    if n_passes <= 3 {
+        // Only random passes if n_passes <= 3
+        for _ in 0..n_passes {
+            pass_sequence.push(PassType::Random)
+        }
+    }
+    // First fill it with Patterns, shuffle it, then evenly distribute Random
+    else {
+        let n_full_arrays = n_passes / PATTERNS.len(); // How many times can we go through all the patterns?
+        let remainder = n_passes % PATTERNS.len(); // How many do we get through on our last time through?
+
+        for _ in 0..n_full_arrays {
+            for p in &PATTERNS {
+                pass_sequence.push(PassType::Pattern(*p));
+            }
+        }
+        for pattern in PATTERNS.iter().take(remainder) {
+            pass_sequence.push(PassType::Pattern(pattern));
+        }
+        let mut rng = rand::thread_rng();
+        pass_sequence.shuffle(&mut rng); // randomize the order of application
+
+        let n_random = 3 + n_passes / 10; // Minimum 3 random passes; ratio of 10 after
+                                          // Evenly space random passes; ensures one at the beginning and end
+        for i in 0..n_random {
+            pass_sequence[i * (n_passes - 1) / (n_random - 1)] = PassType::Random;
+        }
+    }
+
+    // --zero specifies whether we want one final pass of 0x00 on our file
+    if zero {
+        pass_sequence.push(PassType::Pattern(b"\x00"));
+    }
+
+    {
+        let total_passes: usize = pass_sequence.len();
+        let mut file: File = match OpenOptions::new().write(true).truncate(false).open(path) {
+            Ok(f) => f,
+            Err(e) => {
+                show_error!("{}: failed to open for writing: {}", path.display(), e);
+                return;
+            }
+        };
+
+        // NOTE: it does not really matter what we set for total_bytes and gen_type here, so just
+        //       use bogus values
+        let mut generator = BytesGenerator::new(0, PassType::Pattern(&[]), exact);
+
+        for (i, pass_type) in pass_sequence.iter().enumerate() {
+            if verbose {
+                let pass_name: String = pass_name(*pass_type);
+                if total_passes.to_string().len() == 1 {
+                    println!(
+                        "{}: {}: pass {}/{} ({})... ",
+                        NAME,
+                        path.display(),
+                        i + 1,
+                        total_passes,
+                        pass_name
+                    );
+                } else {
+                    println!(
+                        "{}: {}: pass {:2.0}/{:2.0} ({})... ",
+                        NAME,
+                        path.display(),
+                        i + 1,
+                        total_passes,
+                        pass_name
+                    );
+                }
+            }
+            // size is an optional argument for exactly how many bytes we want to shred
+            match do_pass(&mut file, path, &mut generator, *pass_type, size) {
+                Ok(_) => {}
+                Err(e) => {
+                    show_error!("{}: File write pass failed: {}", path.display(), e);
+                }
+            }
+            // Ignore failed writes; just keep trying
+        }
+    }
+
+    if remove {
+        match do_remove(path, path_str, verbose) {
+            Ok(_) => {}
+            Err(e) => {
+                show_error!("{}: failed to remove file: {}", path.display(), e);
+            }
+        }
+    }
+}
+
+fn do_pass<'a>(
+    file: &mut File,
+    path: &Path,
+    generator: &mut BytesGenerator<'a>,
+    generator_type: PassType<'a>,
+    given_file_size: Option<u64>,
+) -> Result<(), io::Error> {
+    file.seek(SeekFrom::Start(0))?;
+
+    // Use the given size or the whole file if not specified
+    let size: u64 = given_file_size.unwrap_or(get_file_size(path)?);
+
+    generator.reset(size, generator_type);
+
+    while let Some(block) = generator.next() {
+        file.write_all(block)?;
+    }
+
+    file.sync_data()?;
+
+    Ok(())
+}
+
+fn get_file_size(path: &Path) -> Result<u64, io::Error> {
+    let size: u64 = fs::metadata(path)?.len();
+
+    Ok(size)
+}
+
+// Repeatedly renames the file with strings of decreasing length (most likely all 0s)
+// Return the path of the file after its last renaming or None if error
+fn wipe_name(orig_path: &Path, verbose: bool) -> Option<PathBuf> {
+    let file_name_len: usize = orig_path.file_name().unwrap().to_str().unwrap().len();
+
+    let mut last_path: PathBuf = PathBuf::from(orig_path);
+
+    for length in (1..=file_name_len).rev() {
+        for name in FilenameGenerator::new(length) {
+            let new_path: PathBuf = orig_path.with_file_name(name);
+            // We don't want the filename to already exist (don't overwrite)
+            // If it does, find another name that doesn't
+            if new_path.exists() {
+                continue;
+            }
+            match fs::rename(&last_path, &new_path) {
+                Ok(()) => {
+                    if verbose {
+                        println!(
+                            "{}: {}: renamed to {}",
+                            NAME,
+                            last_path.display(),
+                            new_path.display()
+                        );
+                    }
+
+                    // Sync every file rename
+                    {
+                        let new_file: File = File::open(new_path.clone())
+                            .expect("Failed to open renamed file for syncing");
+                        new_file.sync_all().expect("Failed to sync renamed file");
+                    }
+
+                    last_path = new_path;
+                    break;
+                }
+                Err(e) => {
+                    println!(
+                        "{}: {}: Couldn't rename to {}: {}",
+                        NAME,
+                        last_path.display(),
+                        new_path.display(),
+                        e
+                    );
+                    return None;
+                }
+            }
+        } // If every possible filename already exists, just reduce the length and try again
+    }
+
+    Some(last_path)
+}
+
+fn do_remove(path: &Path, orig_filename: &str, verbose: bool) -> Result<(), io::Error> {
+    if verbose {
+        println!("{}: {}: removing", NAME, orig_filename);
+    }
+
+    let renamed_path: Option<PathBuf> = wipe_name(path, verbose);
+    if let Some(rp) = renamed_path {
+        fs::remove_file(rp)?;
+    }
+
+    if verbose {
+        println!("{}: {}: removed", NAME, orig_filename);
+    }
+
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_shuf/shuf.rs.html b/src/uu_shuf/shuf.rs.html new file mode 100644 index 000000000..2e5d54ec3 --- /dev/null +++ b/src/uu_shuf/shuf.rs.html @@ -0,0 +1,635 @@ +shuf.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) cmdline evec seps rvec fdata
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use rand::Rng;
+use std::fs::File;
+use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
+use uucore::InvalidEncodingHandling;
+
+enum Mode {
+    Default(String),
+    Echo(Vec<String>),
+    InputRange((usize, usize)),
+}
+
+static NAME: &str = "shuf";
+static USAGE: &str = r#"shuf [OPTION]... [FILE]
+  or:  shuf -e [OPTION]... [ARG]...
+  or:  shuf -i LO-HI [OPTION]...
+Write a random permutation of the input lines to standard output.
+
+With no FILE, or when FILE is -, read standard input.
+"#;
+static TEMPLATE: &str = "Usage: {usage}\nMandatory arguments to long options are mandatory for short options too.\n{unified}";
+
+struct Options {
+    head_count: usize,
+    output: Option<String>,
+    random_source: Option<String>,
+    repeat: bool,
+    sep: u8,
+}
+
+mod options {
+    pub static ECHO: &str = "echo";
+    pub static INPUT_RANGE: &str = "input-range";
+    pub static HEAD_COUNT: &str = "head-count";
+    pub static OUTPUT: &str = "output";
+    pub static RANDOM_SOURCE: &str = "random-source";
+    pub static REPEAT: &str = "repeat";
+    pub static ZERO_TERMINATED: &str = "zero-terminated";
+    pub static FILE: &str = "file";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let mode = if let Some(args) = matches.values_of(options::ECHO) {
+        Mode::Echo(args.map(String::from).collect())
+    } else if let Some(range) = matches.value_of(options::INPUT_RANGE) {
+        match parse_range(range) {
+            Ok(m) => Mode::InputRange(m),
+            Err(msg) => {
+                crash!(1, "{}", msg);
+            }
+        }
+    } else {
+        Mode::Default(matches.value_of(options::FILE).unwrap_or("-").to_string())
+    };
+
+    let options = Options {
+        head_count: match matches.value_of(options::HEAD_COUNT) {
+            Some(count) => match count.parse::<usize>() {
+                Ok(val) => val,
+                Err(_) => {
+                    show_error!("invalid line count: '{}'", count);
+                    return 1;
+                }
+            },
+            None => std::usize::MAX,
+        },
+        output: matches.value_of(options::OUTPUT).map(String::from),
+        random_source: matches.value_of(options::RANDOM_SOURCE).map(String::from),
+        repeat: matches.is_present(options::REPEAT),
+        sep: if matches.is_present(options::ZERO_TERMINATED) {
+            0x00_u8
+        } else {
+            0x0a_u8
+        },
+    };
+
+    match mode {
+        Mode::Echo(args) => {
+            let mut evec = args.iter().map(String::as_bytes).collect::<Vec<_>>();
+            find_seps(&mut evec, options.sep);
+            shuf_bytes(&mut evec, options);
+        }
+        Mode::InputRange((b, e)) => {
+            let rvec = (b..e).map(|x| format!("{}", x)).collect::<Vec<String>>();
+            let mut rvec = rvec.iter().map(String::as_bytes).collect::<Vec<&[u8]>>();
+            shuf_bytes(&mut rvec, options);
+        }
+        Mode::Default(filename) => {
+            let fdata = read_input_file(&filename);
+            let mut fdata = vec![&fdata[..]];
+            find_seps(&mut fdata, options.sep);
+            shuf_bytes(&mut fdata, options);
+        }
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .template(TEMPLATE)
+        .usage(USAGE)
+        .arg(
+            Arg::with_name(options::ECHO)
+                .short("e")
+                .long(options::ECHO)
+                .takes_value(true)
+                .value_name("ARG")
+                .help("treat each ARG as an input line")
+                .multiple(true)
+                .use_delimiter(false)
+                .min_values(0)
+                .conflicts_with(options::INPUT_RANGE),
+        )
+        .arg(
+            Arg::with_name(options::INPUT_RANGE)
+                .short("i")
+                .long(options::INPUT_RANGE)
+                .takes_value(true)
+                .value_name("LO-HI")
+                .help("treat each number LO through HI as an input line")
+                .conflicts_with(options::FILE),
+        )
+        .arg(
+            Arg::with_name(options::HEAD_COUNT)
+                .short("n")
+                .long(options::HEAD_COUNT)
+                .takes_value(true)
+                .value_name("COUNT")
+                .help("output at most COUNT lines"),
+        )
+        .arg(
+            Arg::with_name(options::OUTPUT)
+                .short("o")
+                .long(options::OUTPUT)
+                .takes_value(true)
+                .value_name("FILE")
+                .help("write result to FILE instead of standard output"),
+        )
+        .arg(
+            Arg::with_name(options::RANDOM_SOURCE)
+                .long(options::RANDOM_SOURCE)
+                .takes_value(true)
+                .value_name("FILE")
+                .help("get random bytes from FILE"),
+        )
+        .arg(
+            Arg::with_name(options::REPEAT)
+                .short("r")
+                .long(options::REPEAT)
+                .help("output lines can be repeated"),
+        )
+        .arg(
+            Arg::with_name(options::ZERO_TERMINATED)
+                .short("z")
+                .long(options::ZERO_TERMINATED)
+                .help("line delimiter is NUL, not newline"),
+        )
+        .arg(Arg::with_name(options::FILE).takes_value(true))
+}
+
+fn read_input_file(filename: &str) -> Vec<u8> {
+    let mut file = BufReader::new(if filename == "-" {
+        Box::new(stdin()) as Box<dyn Read>
+    } else {
+        match File::open(filename) {
+            Ok(f) => Box::new(f) as Box<dyn Read>,
+            Err(e) => crash!(1, "failed to open '{}': {}", filename, e),
+        }
+    });
+
+    let mut data = Vec::new();
+    if let Err(e) = file.read_to_end(&mut data) {
+        crash!(1, "failed reading '{}': {}", filename, e)
+    };
+
+    data
+}
+
+fn find_seps(data: &mut Vec<&[u8]>, sep: u8) {
+    // need to use for loop so we don't borrow the vector as we modify it in place
+    // basic idea:
+    // * We don't care about the order of the result. This lets us slice the slices
+    //   without making a new vector.
+    // * Starting from the end of the vector, we examine each element.
+    // * If that element contains the separator, we remove it from the vector,
+    //   and then sub-slice it into slices that do not contain the separator.
+    // * We maintain the invariant throughout that each element in the vector past
+    //   the ith element does not have any separators remaining.
+    for i in (0..data.len()).rev() {
+        if data[i].contains(&sep) {
+            let this = data.swap_remove(i);
+            let mut p = 0;
+            let mut i = 1;
+            loop {
+                if i == this.len() {
+                    break;
+                }
+
+                if this[i] == sep {
+                    data.push(&this[p..i]);
+                    p = i + 1;
+                }
+                i += 1;
+            }
+            if p < this.len() {
+                data.push(&this[p..i]);
+            }
+        }
+    }
+}
+
+fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) {
+    let mut output = BufWriter::new(match opts.output {
+        None => Box::new(stdout()) as Box<dyn Write>,
+        Some(s) => match File::create(&s[..]) {
+            Ok(f) => Box::new(f) as Box<dyn Write>,
+            Err(e) => crash!(1, "failed to open '{}' for writing: {}", &s[..], e),
+        },
+    });
+
+    let mut rng = match opts.random_source {
+        Some(r) => WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new(
+            match File::open(&r[..]) {
+                Ok(f) => f,
+                Err(e) => crash!(1, "failed to open random source '{}': {}", &r[..], e),
+            },
+        )),
+        None => WrappedRng::RngDefault(rand::thread_rng()),
+    };
+
+    // we're generating a random usize. To keep things fair, we take this number mod ceil(log2(length+1))
+    let mut len_mod = 1;
+    let mut len = input.len();
+    while len > 0 {
+        len >>= 1;
+        len_mod <<= 1;
+    }
+
+    let mut count = opts.head_count;
+    while count > 0 && !input.is_empty() {
+        let mut r = input.len();
+        while r >= input.len() {
+            r = rng.next_usize() % len_mod;
+        }
+
+        // write the randomly chosen value and the separator
+        output
+            .write_all(input[r])
+            .unwrap_or_else(|e| crash!(1, "write failed: {}", e));
+        output
+            .write_all(&[opts.sep])
+            .unwrap_or_else(|e| crash!(1, "write failed: {}", e));
+
+        // if we do not allow repeats, remove the chosen value from the input vector
+        if !opts.repeat {
+            // shrink the mask if we will drop below a power of 2
+            if input.len() % 2 == 0 && len_mod > 2 {
+                len_mod >>= 1;
+            }
+            input.swap_remove(r);
+        }
+
+        count -= 1;
+    }
+}
+
+fn parse_range(input_range: &str) -> Result<(usize, usize), String> {
+    let split: Vec<&str> = input_range.split('-').collect();
+    if split.len() != 2 {
+        Err(format!("invalid input range: '{}'", input_range))
+    } else {
+        let begin = split[0]
+            .parse::<usize>()
+            .map_err(|_| format!("invalid input range: '{}'", split[0]))?;
+        let end = split[1]
+            .parse::<usize>()
+            .map_err(|_| format!("invalid input range: '{}'", split[1]))?;
+        Ok((begin, end + 1))
+    }
+}
+
+enum WrappedRng {
+    RngFile(rand::rngs::adapter::ReadRng<File>),
+    RngDefault(rand::rngs::ThreadRng),
+}
+
+impl WrappedRng {
+    fn next_usize(&mut self) -> usize {
+        match *self {
+            WrappedRng::RngFile(ref mut r) => r.gen(),
+            WrappedRng::RngDefault(ref mut r) => r.gen(),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sleep/sleep.rs.html b/src/uu_sleep/sleep.rs.html new file mode 100644 index 000000000..af1f375cb --- /dev/null +++ b/src/uu_sleep/sleep.rs.html @@ -0,0 +1,161 @@ +sleep.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use std::thread;
+use std::time::Duration;
+
+use uucore::error::{UResult, USimpleError};
+
+use clap::{crate_version, App, Arg};
+
+static ABOUT: &str = "Pause for NUMBER seconds.";
+static LONG_HELP: &str = "Pause for NUMBER seconds.  SUFFIX may be 's' for seconds (the default),
+'m' for minutes, 'h' for hours or 'd' for days.  Unlike most implementations
+that require NUMBER be an integer, here NUMBER may be an arbitrary floating
+point number.  Given two or more arguments, pause for the amount of time
+specified by the sum of their values.";
+
+mod options {
+    pub const NUMBER: &str = "NUMBER";
+}
+
+fn usage() -> String {
+    format!(
+        "{0} {1}[SUFFIX]... \n    {0} OPTION",
+        uucore::execution_phrase(),
+        options::NUMBER
+    )
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    if let Some(values) = matches.values_of(options::NUMBER) {
+        let numbers = values.collect();
+        return sleep(numbers);
+    }
+
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(LONG_HELP)
+        .arg(
+            Arg::with_name(options::NUMBER)
+                .long(options::NUMBER)
+                .help("pause for NUMBER seconds")
+                .value_name(options::NUMBER)
+                .index(1)
+                .multiple(true)
+                .required(true),
+        )
+}
+
+fn sleep(args: Vec<&str>) -> UResult<()> {
+    let sleep_dur =
+        args.iter().try_fold(
+            Duration::new(0, 0),
+            |result, arg| match uucore::parse_time::from_str(&arg[..]) {
+                Ok(m) => Ok(m + result),
+                Err(f) => Err(USimpleError::new(1, f)),
+            },
+        )?;
+    thread::sleep(sleep_dur);
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/check.rs.html b/src/uu_sort/check.rs.html new file mode 100644 index 000000000..49663c9aa --- /dev/null +++ b/src/uu_sort/check.rs.html @@ -0,0 +1,265 @@ +check.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Debertol <michael.debertol..AT..gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+//! Check if a file is ordered
+
+use crate::{
+    chunks::{self, Chunk, RecycledChunk},
+    compare_by, open, GlobalSettings, SortError,
+};
+use itertools::Itertools;
+use std::{
+    cmp::Ordering,
+    ffi::OsStr,
+    io::Read,
+    iter,
+    sync::mpsc::{sync_channel, Receiver, SyncSender},
+    thread,
+};
+use uucore::error::UResult;
+
+/// Check if the file at `path` is ordered.
+///
+/// # Returns
+///
+/// The code we should exit with.
+pub fn check(path: &OsStr, settings: &GlobalSettings) -> UResult<()> {
+    let max_allowed_cmp = if settings.unique {
+        // If `unique` is enabled, the previous line must compare _less_ to the next one.
+        Ordering::Less
+    } else {
+        // Otherwise, the line previous line must compare _less or equal_ to the next one.
+        Ordering::Equal
+    };
+    let file = open(path)?;
+    let (recycled_sender, recycled_receiver) = sync_channel(2);
+    let (loaded_sender, loaded_receiver) = sync_channel(2);
+    thread::spawn({
+        let settings = settings.clone();
+        move || reader(file, recycled_receiver, loaded_sender, &settings)
+    });
+    for _ in 0..2 {
+        let _ = recycled_sender.send(RecycledChunk::new(if settings.buffer_size < 100 * 1024 {
+            // when the buffer size is smaller than 100KiB we choose it instead of the default.
+            // this improves testability.
+            settings.buffer_size
+        } else {
+            100 * 1024
+        }));
+    }
+
+    let mut prev_chunk: Option<Chunk> = None;
+    let mut line_idx = 0;
+    for chunk in loaded_receiver.iter() {
+        line_idx += 1;
+        if let Some(prev_chunk) = prev_chunk.take() {
+            // Check if the first element of the new chunk is greater than the last
+            // element from the previous chunk
+            let prev_last = prev_chunk.lines().last().unwrap();
+            let new_first = chunk.lines().first().unwrap();
+
+            if compare_by(
+                prev_last,
+                new_first,
+                settings,
+                prev_chunk.line_data(),
+                chunk.line_data(),
+            ) > max_allowed_cmp
+            {
+                return Err(SortError::Disorder {
+                    file: path.to_owned(),
+                    line_number: line_idx,
+                    line: new_first.line.to_owned(),
+                    silent: settings.check_silent,
+                }
+                .into());
+            }
+            let _ = recycled_sender.send(prev_chunk.recycle());
+        }
+
+        for (a, b) in chunk.lines().iter().tuple_windows() {
+            line_idx += 1;
+            if compare_by(a, b, settings, chunk.line_data(), chunk.line_data()) > max_allowed_cmp {
+                return Err(SortError::Disorder {
+                    file: path.to_owned(),
+                    line_number: line_idx,
+                    line: b.line.to_owned(),
+                    silent: settings.check_silent,
+                }
+                .into());
+            }
+        }
+
+        prev_chunk = Some(chunk);
+    }
+    Ok(())
+}
+
+/// The function running on the reader thread.
+fn reader(
+    mut file: Box<dyn Read + Send>,
+    receiver: Receiver<RecycledChunk>,
+    sender: SyncSender<Chunk>,
+    settings: &GlobalSettings,
+) -> UResult<()> {
+    let mut carry_over = vec![];
+    for recycled_chunk in receiver.iter() {
+        let should_continue = chunks::read(
+            &sender,
+            recycled_chunk,
+            None,
+            &mut carry_over,
+            &mut file,
+            &mut iter::empty(),
+            if settings.zero_terminated {
+                b'\0'
+            } else {
+                b'\n'
+            },
+            settings,
+        )?;
+        if !should_continue {
+            break;
+        }
+    }
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/chunks.rs.html b/src/uu_sort/chunks.rs.html new file mode 100644 index 000000000..0bda92b77 --- /dev/null +++ b/src/uu_sort/chunks.rs.html @@ -0,0 +1,647 @@ +chunks.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Debertol <michael.debertol..AT..gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+//! Utilities for reading files as chunks.
+
+use std::{
+    io::{ErrorKind, Read},
+    sync::mpsc::SyncSender,
+};
+
+use memchr::memchr_iter;
+use ouroboros::self_referencing;
+use uucore::error::{UResult, USimpleError};
+
+use crate::{numeric_str_cmp::NumInfo, GeneralF64ParseResult, GlobalSettings, Line, SortError};
+
+/// The chunk that is passed around between threads.
+/// `lines` consist of slices into `buffer`.
+#[self_referencing(pub_extras)]
+#[derive(Debug)]
+pub struct Chunk {
+    pub buffer: Vec<u8>,
+    #[borrows(buffer)]
+    #[covariant]
+    pub contents: ChunkContents<'this>,
+}
+
+#[derive(Debug)]
+pub struct ChunkContents<'a> {
+    pub lines: Vec<Line<'a>>,
+    pub line_data: LineData<'a>,
+}
+
+#[derive(Debug)]
+pub struct LineData<'a> {
+    pub selections: Vec<&'a str>,
+    pub num_infos: Vec<NumInfo>,
+    pub parsed_floats: Vec<GeneralF64ParseResult>,
+}
+
+impl Chunk {
+    /// Destroy this chunk and return its components to be reused.
+    pub fn recycle(mut self) -> RecycledChunk {
+        let recycled_contents = self.with_contents_mut(|contents| {
+            contents.lines.clear();
+            contents.line_data.selections.clear();
+            contents.line_data.num_infos.clear();
+            contents.line_data.parsed_floats.clear();
+            let lines = unsafe {
+                // SAFETY: It is safe to (temporarily) transmute to a vector of lines with a longer lifetime,
+                // because the vector is empty.
+                // Transmuting is necessary to make recycling possible. See https://github.com/rust-lang/rfcs/pull/2802
+                // for a rfc to make this unnecessary. Its example is similar to the code here.
+                std::mem::transmute::<Vec<Line<'_>>, Vec<Line<'static>>>(std::mem::take(
+                    &mut contents.lines,
+                ))
+            };
+            let selections = unsafe {
+                // SAFETY: (same as above) It is safe to (temporarily) transmute to a vector of &str with a longer lifetime,
+                // because the vector is empty.
+                std::mem::transmute::<Vec<&'_ str>, Vec<&'static str>>(std::mem::take(
+                    &mut contents.line_data.selections,
+                ))
+            };
+            (
+                lines,
+                selections,
+                std::mem::take(&mut contents.line_data.num_infos),
+                std::mem::take(&mut contents.line_data.parsed_floats),
+            )
+        });
+        RecycledChunk {
+            lines: recycled_contents.0,
+            selections: recycled_contents.1,
+            num_infos: recycled_contents.2,
+            parsed_floats: recycled_contents.3,
+            buffer: self.into_heads().buffer,
+        }
+    }
+
+    pub fn lines(&self) -> &Vec<Line> {
+        &self.borrow_contents().lines
+    }
+    pub fn line_data(&self) -> &LineData {
+        &self.borrow_contents().line_data
+    }
+}
+
+pub struct RecycledChunk {
+    lines: Vec<Line<'static>>,
+    selections: Vec<&'static str>,
+    num_infos: Vec<NumInfo>,
+    parsed_floats: Vec<GeneralF64ParseResult>,
+    buffer: Vec<u8>,
+}
+
+impl RecycledChunk {
+    pub fn new(capacity: usize) -> Self {
+        RecycledChunk {
+            lines: Vec::new(),
+            selections: Vec::new(),
+            num_infos: Vec::new(),
+            parsed_floats: Vec::new(),
+            buffer: vec![0; capacity],
+        }
+    }
+}
+
+/// Read a chunk, parse lines and send them.
+///
+/// No empty chunk will be sent. If we reach the end of the input, `false` is returned.
+/// However, if this function returns `true`, it is not guaranteed that there is still
+/// input left: If the input fits _exactly_ into a buffer, we will only notice that there's
+/// nothing more to read at the next invocation. In case there is no input left, nothing will
+/// be sent.
+///
+/// # Arguments
+///
+/// (see also `read_to_chunk` for a more detailed documentation)
+///
+/// * `sender`: The sender to send the lines to the sorter.
+/// * `recycled_chunk`: The recycled chunk, as returned by `Chunk::recycle`.
+///   (i.e. `buffer.len()` should be equal to `buffer.capacity()`)
+/// * `max_buffer_size`: How big `buffer` can be.
+/// * `carry_over`: The bytes that must be carried over in between invocations.
+/// * `file`: The current file.
+/// * `next_files`: What `file` should be updated to next.
+/// * `separator`: The line separator.
+/// * `settings`: The global settings.
+#[allow(clippy::too_many_arguments)]
+pub fn read<T: Read>(
+    sender: &SyncSender<Chunk>,
+    recycled_chunk: RecycledChunk,
+    max_buffer_size: Option<usize>,
+    carry_over: &mut Vec<u8>,
+    file: &mut T,
+    next_files: &mut impl Iterator<Item = UResult<T>>,
+    separator: u8,
+    settings: &GlobalSettings,
+) -> UResult<bool> {
+    let RecycledChunk {
+        lines,
+        selections,
+        num_infos,
+        parsed_floats,
+        mut buffer,
+    } = recycled_chunk;
+    if buffer.len() < carry_over.len() {
+        buffer.resize(carry_over.len() + 10 * 1024, 0);
+    }
+    buffer[..carry_over.len()].copy_from_slice(carry_over);
+    let (read, should_continue) = read_to_buffer(
+        file,
+        next_files,
+        &mut buffer,
+        max_buffer_size,
+        carry_over.len(),
+        separator,
+    )?;
+    carry_over.clear();
+    carry_over.extend_from_slice(&buffer[read..]);
+
+    if read != 0 {
+        let payload: UResult<Chunk> = Chunk::try_new(buffer, |buffer| {
+            let selections = unsafe {
+                // SAFETY: It is safe to transmute to an empty vector of selections with shorter lifetime.
+                // It was only temporarily transmuted to a Vec<Line<'static>> to make recycling possible.
+                std::mem::transmute::<Vec<&'static str>, Vec<&'_ str>>(selections)
+            };
+            let mut lines = unsafe {
+                // SAFETY: (same as above) It is safe to transmute to a vector of lines with shorter lifetime,
+                // because it was only temporarily transmuted to a Vec<Line<'static>> to make recycling possible.
+                std::mem::transmute::<Vec<Line<'static>>, Vec<Line<'_>>>(lines)
+            };
+            let read = std::str::from_utf8(&buffer[..read])
+                .map_err(|error| SortError::Uft8Error { error })?;
+            let mut line_data = LineData {
+                selections,
+                num_infos,
+                parsed_floats,
+            };
+            parse_lines(read, &mut lines, &mut line_data, separator, settings);
+            Ok(ChunkContents { lines, line_data })
+        });
+        sender.send(payload?).unwrap();
+    }
+    Ok(should_continue)
+}
+
+/// Split `read` into `Line`s, and add them to `lines`.
+fn parse_lines<'a>(
+    mut read: &'a str,
+    lines: &mut Vec<Line<'a>>,
+    line_data: &mut LineData<'a>,
+    separator: u8,
+    settings: &GlobalSettings,
+) {
+    // Strip a trailing separator. TODO: Once our MinRustV is 1.45 or above, use strip_suffix() instead.
+    if read.ends_with(separator as char) {
+        read = &read[..read.len() - 1];
+    }
+
+    assert!(lines.is_empty());
+    assert!(line_data.selections.is_empty());
+    assert!(line_data.num_infos.is_empty());
+    assert!(line_data.parsed_floats.is_empty());
+    let mut token_buffer = vec![];
+    lines.extend(
+        read.split(separator as char)
+            .enumerate()
+            .map(|(index, line)| Line::create(line, index, line_data, &mut token_buffer, settings)),
+    );
+}
+
+/// Read from `file` into `buffer`.
+///
+/// This function makes sure that at least two lines are read (unless we reach EOF and there's no next file),
+/// growing the buffer if necessary.
+/// The last line is likely to not have been fully read into the buffer. Its bytes must be copied to
+/// the front of the buffer for the next invocation so that it can be continued to be read
+/// (see the return values and `start_offset`).
+///
+/// # Arguments
+///
+/// * `file`: The file to start reading from.
+/// * `next_files`: When `file` reaches EOF, it is updated to `next_files.next()` if that is `Some`,
+///    and this function continues reading.
+/// * `buffer`: The buffer that is filled with bytes. Its contents will mostly be overwritten (see `start_offset`
+///   as well). It will be grown up to `max_buffer_size` if necessary, but it will always grow to read at least two lines.
+/// * `max_buffer_size`: Grow the buffer to at most this length. If None, the buffer will not grow, unless needed to read at least two lines.
+/// * `start_offset`: The amount of bytes at the start of `buffer` that were carried over
+///    from the previous read and should not be overwritten.
+/// * `separator`: The byte that separates lines.
+///
+/// # Returns
+///
+/// * The amount of bytes in `buffer` that can now be interpreted as lines.
+///   The remaining bytes must be copied to the start of the buffer for the next invocation,
+///   if another invocation is necessary, which is determined by the other return value.
+/// * Whether this function should be called again.
+fn read_to_buffer<T: Read>(
+    file: &mut T,
+    next_files: &mut impl Iterator<Item = UResult<T>>,
+    buffer: &mut Vec<u8>,
+    max_buffer_size: Option<usize>,
+    start_offset: usize,
+    separator: u8,
+) -> UResult<(usize, bool)> {
+    let mut read_target = &mut buffer[start_offset..];
+    let mut last_file_target_size = read_target.len();
+    loop {
+        match file.read(read_target) {
+            Ok(0) => {
+                if read_target.is_empty() {
+                    // chunk is full
+                    if let Some(max_buffer_size) = max_buffer_size {
+                        if max_buffer_size > buffer.len() {
+                            // we can grow the buffer
+                            let prev_len = buffer.len();
+                            if buffer.len() < max_buffer_size / 2 {
+                                buffer.resize(buffer.len() * 2, 0);
+                            } else {
+                                buffer.resize(max_buffer_size, 0);
+                            }
+                            read_target = &mut buffer[prev_len..];
+                            continue;
+                        }
+                    }
+                    let mut sep_iter = memchr_iter(separator, buffer).rev();
+                    let last_line_end = sep_iter.next();
+                    if sep_iter.next().is_some() {
+                        // We read enough lines.
+                        let end = last_line_end.unwrap();
+                        // We want to include the separator here, because it shouldn't be carried over.
+                        return Ok((end + 1, true));
+                    } else {
+                        // We need to read more lines
+                        let len = buffer.len();
+                        // resize the vector to 10 KB more
+                        buffer.resize(len + 1024 * 10, 0);
+                        read_target = &mut buffer[len..];
+                    }
+                } else {
+                    // This file has been fully read.
+                    let mut leftover_len = read_target.len();
+                    if last_file_target_size != leftover_len {
+                        // The file was not empty.
+                        let read_len = buffer.len() - leftover_len;
+                        if buffer[read_len - 1] != separator {
+                            // The file did not end with a separator. We have to insert one.
+                            buffer[read_len] = separator;
+                            leftover_len -= 1;
+                        }
+                        let read_len = buffer.len() - leftover_len;
+                        read_target = &mut buffer[read_len..];
+                    }
+                    if let Some(next_file) = next_files.next() {
+                        // There is another file.
+                        last_file_target_size = leftover_len;
+                        *file = next_file?;
+                    } else {
+                        // This was the last file.
+                        let read_len = buffer.len() - leftover_len;
+                        return Ok((read_len, false));
+                    }
+                }
+            }
+            Ok(n) => {
+                read_target = &mut read_target[n..];
+            }
+            Err(e) if e.kind() == ErrorKind::Interrupted => {
+                // retry
+            }
+            Err(e) => return Err(USimpleError::new(2, e.to_string())),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/custom_str_cmp.rs.html b/src/uu_sort/custom_str_cmp.rs.html new file mode 100644 index 000000000..83211c8aa --- /dev/null +++ b/src/uu_sort/custom_str_cmp.rs.html @@ -0,0 +1,133 @@ +custom_str_cmp.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Debertol <michael.debertol..AT..gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+//! Custom string comparisons.
+//!
+//! The goal is to compare strings without transforming them first (i.e. not allocating new strings)
+
+use std::cmp::Ordering;
+
+fn filter_char(c: char, ignore_non_printing: bool, ignore_non_dictionary: bool) -> bool {
+    if ignore_non_dictionary && !(c.is_ascii_alphanumeric() || c.is_ascii_whitespace()) {
+        return false;
+    }
+    if ignore_non_printing && (c.is_ascii_control() || !c.is_ascii()) {
+        return false;
+    }
+    true
+}
+
+fn cmp_chars(a: char, b: char, ignore_case: bool) -> Ordering {
+    if ignore_case {
+        a.to_ascii_uppercase().cmp(&b.to_ascii_uppercase())
+    } else {
+        a.cmp(&b)
+    }
+}
+
+pub fn custom_str_cmp(
+    a: &str,
+    b: &str,
+    ignore_non_printing: bool,
+    ignore_non_dictionary: bool,
+    ignore_case: bool,
+) -> Ordering {
+    if !(ignore_case || ignore_non_dictionary || ignore_non_printing) {
+        // There are no custom settings. Fall back to the default strcmp, which is faster.
+        return a.cmp(b);
+    }
+    let mut a_chars = a
+        .chars()
+        .filter(|&c| filter_char(c, ignore_non_printing, ignore_non_dictionary));
+    let mut b_chars = b
+        .chars()
+        .filter(|&c| filter_char(c, ignore_non_printing, ignore_non_dictionary));
+    loop {
+        let a_char = a_chars.next();
+        let b_char = b_chars.next();
+        match (a_char, b_char) {
+            (None, None) => return Ordering::Equal,
+            (Some(_), None) => return Ordering::Greater,
+            (None, Some(_)) => return Ordering::Less,
+            (Some(a_char), Some(b_char)) => {
+                let ordering = cmp_chars(a_char, b_char, ignore_case);
+                if ordering != Ordering::Equal {
+                    return ordering;
+                }
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/ext_sort.rs.html b/src/uu_sort/ext_sort.rs.html new file mode 100644 index 000000000..eb505785f --- /dev/null +++ b/src/uu_sort/ext_sort.rs.html @@ -0,0 +1,577 @@ +ext_sort.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Debertol <michael.debertol..AT..gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+//! Sort big files by using auxiliary files for storing intermediate chunks.
+//!
+//! Files are read into chunks of memory which are then sorted individually and
+//! written to temporary files. There are two threads: One sorter, and one reader/writer.
+//! The buffers for the individual chunks are recycled. There are two buffers.
+
+use std::cmp::Ordering;
+use std::fs::File;
+use std::io::Write;
+use std::path::PathBuf;
+use std::{
+    io::Read,
+    sync::mpsc::{Receiver, SyncSender},
+    thread,
+};
+
+use itertools::Itertools;
+use uucore::error::UResult;
+
+use crate::chunks::RecycledChunk;
+use crate::merge::ClosedTmpFile;
+use crate::merge::WriteableCompressedTmpFile;
+use crate::merge::WriteablePlainTmpFile;
+use crate::merge::WriteableTmpFile;
+use crate::tmp_dir::TmpDirWrapper;
+use crate::Output;
+use crate::{
+    chunks::{self, Chunk},
+    compare_by, merge, sort_by, GlobalSettings,
+};
+use crate::{print_sorted, Line};
+
+const START_BUFFER_SIZE: usize = 8_000;
+
+/// Sort files by using auxiliary files for storing intermediate chunks (if needed), and output the result.
+pub fn ext_sort(
+    files: &mut impl Iterator<Item = UResult<Box<dyn Read + Send>>>,
+    settings: &GlobalSettings,
+    output: Output,
+    tmp_dir: &mut TmpDirWrapper,
+) -> UResult<()> {
+    let (sorted_sender, sorted_receiver) = std::sync::mpsc::sync_channel(1);
+    let (recycled_sender, recycled_receiver) = std::sync::mpsc::sync_channel(1);
+    thread::spawn({
+        let settings = settings.clone();
+        move || sorter(recycled_receiver, sorted_sender, settings)
+    });
+    if settings.compress_prog.is_some() {
+        reader_writer::<_, WriteableCompressedTmpFile>(
+            files,
+            settings,
+            sorted_receiver,
+            recycled_sender,
+            output,
+            tmp_dir,
+        )
+    } else {
+        reader_writer::<_, WriteablePlainTmpFile>(
+            files,
+            settings,
+            sorted_receiver,
+            recycled_sender,
+            output,
+            tmp_dir,
+        )
+    }
+}
+
+fn reader_writer<
+    F: Iterator<Item = UResult<Box<dyn Read + Send>>>,
+    Tmp: WriteableTmpFile + 'static,
+>(
+    files: F,
+    settings: &GlobalSettings,
+    receiver: Receiver<Chunk>,
+    sender: SyncSender<Chunk>,
+    output: Output,
+    tmp_dir: &mut TmpDirWrapper,
+) -> UResult<()> {
+    let separator = if settings.zero_terminated {
+        b'\0'
+    } else {
+        b'\n'
+    };
+
+    // Heuristically chosen: Dividing by 10 seems to keep our memory usage roughly
+    // around settings.buffer_size as a whole.
+    let buffer_size = settings.buffer_size / 10;
+    let read_result: ReadResult<Tmp> = read_write_loop(
+        files,
+        tmp_dir,
+        separator,
+        buffer_size,
+        settings,
+        receiver,
+        sender,
+    )?;
+    match read_result {
+        ReadResult::WroteChunksToFile { tmp_files } => {
+            let merger = merge::merge_with_file_limit::<_, _, Tmp>(
+                tmp_files.into_iter().map(|c| c.reopen()),
+                settings,
+                tmp_dir,
+            )?;
+            merger.write_all(settings, output)?;
+        }
+        ReadResult::SortedSingleChunk(chunk) => {
+            if settings.unique {
+                print_sorted(
+                    chunk.lines().iter().dedup_by(|a, b| {
+                        compare_by(a, b, settings, chunk.line_data(), chunk.line_data())
+                            == Ordering::Equal
+                    }),
+                    settings,
+                    output,
+                );
+            } else {
+                print_sorted(chunk.lines().iter(), settings, output);
+            }
+        }
+        ReadResult::SortedTwoChunks([a, b]) => {
+            let merged_iter = a.lines().iter().map(|line| (line, &a)).merge_by(
+                b.lines().iter().map(|line| (line, &b)),
+                |(line_a, a), (line_b, b)| {
+                    compare_by(line_a, line_b, settings, a.line_data(), b.line_data())
+                        != Ordering::Greater
+                },
+            );
+            if settings.unique {
+                print_sorted(
+                    merged_iter
+                        .dedup_by(|(line_a, a), (line_b, b)| {
+                            compare_by(line_a, line_b, settings, a.line_data(), b.line_data())
+                                == Ordering::Equal
+                        })
+                        .map(|(line, _)| line),
+                    settings,
+                    output,
+                );
+            } else {
+                print_sorted(merged_iter.map(|(line, _)| line), settings, output);
+            }
+        }
+        ReadResult::EmptyInput => {
+            // don't output anything
+        }
+    }
+    Ok(())
+}
+
+/// The function that is executed on the sorter thread.
+fn sorter(receiver: Receiver<Chunk>, sender: SyncSender<Chunk>, settings: GlobalSettings) {
+    while let Ok(mut payload) = receiver.recv() {
+        payload.with_contents_mut(|contents| {
+            sort_by(&mut contents.lines, &settings, &contents.line_data)
+        });
+        if sender.send(payload).is_err() {
+            // The receiver has gone away, likely because the other thread hit an error.
+            // We stop silently because the actual error is printed by the other thread.
+            return;
+        }
+    }
+}
+
+/// Describes how we read the chunks from the input.
+enum ReadResult<I: WriteableTmpFile> {
+    /// The input was empty. Nothing was read.
+    EmptyInput,
+    /// The input fits into a single Chunk, which was kept in memory.
+    SortedSingleChunk(Chunk),
+    /// The input fits into two chunks, which were kept in memory.
+    SortedTwoChunks([Chunk; 2]),
+    /// The input was read into multiple chunks, which were written to auxiliary files.
+    WroteChunksToFile { tmp_files: Vec<I::Closed> },
+}
+/// The function that is executed on the reader/writer thread.
+fn read_write_loop<I: WriteableTmpFile>(
+    mut files: impl Iterator<Item = UResult<Box<dyn Read + Send>>>,
+    tmp_dir: &mut TmpDirWrapper,
+    separator: u8,
+    buffer_size: usize,
+    settings: &GlobalSettings,
+    receiver: Receiver<Chunk>,
+    sender: SyncSender<Chunk>,
+) -> UResult<ReadResult<I>> {
+    let mut file = files.next().unwrap()?;
+
+    let mut carry_over = vec![];
+    // kick things off with two reads
+    for _ in 0..2 {
+        let should_continue = chunks::read(
+            &sender,
+            RecycledChunk::new(if START_BUFFER_SIZE < buffer_size {
+                START_BUFFER_SIZE
+            } else {
+                buffer_size
+            }),
+            Some(buffer_size),
+            &mut carry_over,
+            &mut file,
+            &mut files,
+            separator,
+            settings,
+        )?;
+
+        if !should_continue {
+            drop(sender);
+            // We have already read the whole input. Since we are in our first two reads,
+            // this means that we can fit the whole input into memory. Bypass writing below and
+            // handle this case in a more straightforward way.
+            return Ok(if let Ok(first_chunk) = receiver.recv() {
+                if let Ok(second_chunk) = receiver.recv() {
+                    ReadResult::SortedTwoChunks([first_chunk, second_chunk])
+                } else {
+                    ReadResult::SortedSingleChunk(first_chunk)
+                }
+            } else {
+                ReadResult::EmptyInput
+            });
+        }
+    }
+
+    let mut sender_option = Some(sender);
+    let mut tmp_files = vec![];
+    loop {
+        let mut chunk = match receiver.recv() {
+            Ok(it) => it,
+            _ => {
+                return Ok(ReadResult::WroteChunksToFile { tmp_files });
+            }
+        };
+
+        let tmp_file = write::<I>(
+            &mut chunk,
+            tmp_dir.next_file()?,
+            settings.compress_prog.as_deref(),
+            separator,
+        )?;
+        tmp_files.push(tmp_file);
+
+        let recycled_chunk = chunk.recycle();
+
+        if let Some(sender) = &sender_option {
+            let should_continue = chunks::read(
+                sender,
+                recycled_chunk,
+                None,
+                &mut carry_over,
+                &mut file,
+                &mut files,
+                separator,
+                settings,
+            )?;
+            if !should_continue {
+                sender_option = None;
+            }
+        }
+    }
+}
+
+/// Write the lines in `chunk` to `file`, separated by `separator`.
+/// `compress_prog` is used to optionally compress file contents.
+fn write<I: WriteableTmpFile>(
+    chunk: &mut Chunk,
+    file: (File, PathBuf),
+    compress_prog: Option<&str>,
+    separator: u8,
+) -> UResult<I::Closed> {
+    let mut tmp_file = I::create(file, compress_prog)?;
+    write_lines(chunk.lines(), tmp_file.as_write(), separator);
+    tmp_file.finished_writing()
+}
+
+fn write_lines<'a, T: Write>(lines: &[Line<'a>], writer: &mut T, separator: u8) {
+    for s in lines {
+        writer.write_all(s.line.as_bytes()).unwrap();
+        writer.write_all(&[separator]).unwrap();
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/merge.rs.html b/src/uu_sort/merge.rs.html new file mode 100644 index 000000000..4463706a8 --- /dev/null +++ b/src/uu_sort/merge.rs.html @@ -0,0 +1,1115 @@ +merge.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+
+//! Merge already sorted files.
+//!
+//! We achieve performance by splitting the tasks of sorting and writing, and reading and parsing between two threads.
+//! The threads communicate over channels. There's one channel per file in the direction reader -> sorter, but only
+//! one channel from the sorter back to the reader. The channels to the sorter are used to send the read chunks.
+//! The sorter reads the next chunk from the channel whenever it needs the next chunk after running out of lines
+//! from the previous read of the file. The channel back from the sorter to the reader has two purposes: To allow the reader
+//! to reuse memory allocations and to tell the reader which file to read from next.
+
+use std::{
+    cmp::Ordering,
+    ffi::OsString,
+    fs::{self, File},
+    io::{BufWriter, Read, Write},
+    iter,
+    path::{Path, PathBuf},
+    process::{Child, ChildStdin, ChildStdout, Command, Stdio},
+    rc::Rc,
+    sync::mpsc::{channel, sync_channel, Receiver, Sender, SyncSender},
+    thread::{self, JoinHandle},
+};
+
+use compare::Compare;
+use itertools::Itertools;
+use uucore::error::UResult;
+
+use crate::{
+    chunks::{self, Chunk, RecycledChunk},
+    compare_by, open,
+    tmp_dir::TmpDirWrapper,
+    GlobalSettings, Output, SortError,
+};
+
+/// If the output file occurs in the input files as well, copy the contents of the output file
+/// and replace its occurrences in the inputs with that copy.
+fn replace_output_file_in_input_files(
+    files: &mut [OsString],
+    output: Option<&str>,
+    tmp_dir: &mut TmpDirWrapper,
+) -> UResult<()> {
+    let mut copy: Option<PathBuf> = None;
+    if let Some(Ok(output_path)) = output.map(|path| Path::new(path).canonicalize()) {
+        for file in files {
+            if let Ok(file_path) = Path::new(file).canonicalize() {
+                if file_path == output_path {
+                    if let Some(copy) = &copy {
+                        *file = copy.clone().into_os_string();
+                    } else {
+                        let (_file, copy_path) = tmp_dir.next_file()?;
+                        std::fs::copy(file_path, &copy_path)
+                            .map_err(|error| SortError::OpenTmpFileFailed { error })?;
+                        *file = copy_path.clone().into_os_string();
+                        copy = Some(copy_path)
+                    }
+                }
+            }
+        }
+    }
+    Ok(())
+}
+
+/// Merge pre-sorted `Box<dyn Read>`s.
+///
+/// If `settings.merge_batch_size` is greater than the length of `files`, intermediate files will be used.
+/// If `settings.compress_prog` is `Some`, intermediate files will be compressed with it.
+pub fn merge<'a>(
+    files: &mut [OsString],
+    settings: &'a GlobalSettings,
+    output: Option<&str>,
+    tmp_dir: &mut TmpDirWrapper,
+) -> UResult<FileMerger<'a>> {
+    replace_output_file_in_input_files(files, output, tmp_dir)?;
+    if settings.compress_prog.is_none() {
+        merge_with_file_limit::<_, _, WriteablePlainTmpFile>(
+            files
+                .iter()
+                .map(|file| open(file).map(|file| PlainMergeInput { inner: file })),
+            settings,
+            tmp_dir,
+        )
+    } else {
+        merge_with_file_limit::<_, _, WriteableCompressedTmpFile>(
+            files
+                .iter()
+                .map(|file| open(file).map(|file| PlainMergeInput { inner: file })),
+            settings,
+            tmp_dir,
+        )
+    }
+}
+
+// Merge already sorted `MergeInput`s.
+pub fn merge_with_file_limit<
+    'a,
+    M: MergeInput + 'static,
+    F: ExactSizeIterator<Item = UResult<M>>,
+    Tmp: WriteableTmpFile + 'static,
+>(
+    files: F,
+    settings: &'a GlobalSettings,
+    tmp_dir: &mut TmpDirWrapper,
+) -> UResult<FileMerger<'a>> {
+    if files.len() > settings.merge_batch_size {
+        let mut remaining_files = files.len();
+        let batches = files.chunks(settings.merge_batch_size);
+        let mut batches = batches.into_iter();
+        let mut temporary_files = vec![];
+        while remaining_files != 0 {
+            // Work around the fact that `Chunks` is not an `ExactSizeIterator`.
+            remaining_files = remaining_files.saturating_sub(settings.merge_batch_size);
+            let merger = merge_without_limit(batches.next().unwrap(), settings)?;
+            let mut tmp_file =
+                Tmp::create(tmp_dir.next_file()?, settings.compress_prog.as_deref())?;
+            merger.write_all_to(settings, tmp_file.as_write())?;
+            temporary_files.push(tmp_file.finished_writing()?);
+        }
+        assert!(batches.next().is_none());
+        merge_with_file_limit::<_, _, Tmp>(
+            temporary_files
+                .into_iter()
+                .map(Box::new(|c: Tmp::Closed| c.reopen())
+                    as Box<
+                        dyn FnMut(Tmp::Closed) -> UResult<<Tmp::Closed as ClosedTmpFile>::Reopened>,
+                    >),
+            settings,
+            tmp_dir,
+        )
+    } else {
+        merge_without_limit(files, settings)
+    }
+}
+
+/// Merge files without limiting how many files are concurrently open.
+///
+/// It is the responsibility of the caller to ensure that `files` yields only
+/// as many files as we are allowed to open concurrently.
+fn merge_without_limit<M: MergeInput + 'static, F: Iterator<Item = UResult<M>>>(
+    files: F,
+    settings: &GlobalSettings,
+) -> UResult<FileMerger> {
+    let (request_sender, request_receiver) = channel();
+    let mut reader_files = Vec::with_capacity(files.size_hint().0);
+    let mut loaded_receivers = Vec::with_capacity(files.size_hint().0);
+    for (file_number, file) in files.enumerate() {
+        let (sender, receiver) = sync_channel(2);
+        loaded_receivers.push(receiver);
+        reader_files.push(Some(ReaderFile {
+            file: file?,
+            sender,
+            carry_over: vec![],
+        }));
+        // Send the initial chunk to trigger a read for each file
+        request_sender
+            .send((file_number, RecycledChunk::new(8 * 1024)))
+            .unwrap();
+    }
+
+    // Send the second chunk for each file
+    for file_number in 0..reader_files.len() {
+        request_sender
+            .send((file_number, RecycledChunk::new(8 * 1024)))
+            .unwrap();
+    }
+
+    let reader_join_handle = thread::spawn({
+        let settings = settings.clone();
+        move || {
+            reader(
+                request_receiver,
+                &mut reader_files,
+                &settings,
+                if settings.zero_terminated {
+                    b'\0'
+                } else {
+                    b'\n'
+                },
+            )
+        }
+    });
+
+    let mut mergeable_files = vec![];
+
+    for (file_number, receiver) in loaded_receivers.into_iter().enumerate() {
+        if let Ok(chunk) = receiver.recv() {
+            mergeable_files.push(MergeableFile {
+                current_chunk: Rc::new(chunk),
+                file_number,
+                line_idx: 0,
+                receiver,
+            })
+        }
+    }
+
+    Ok(FileMerger {
+        heap: binary_heap_plus::BinaryHeap::from_vec_cmp(
+            mergeable_files,
+            FileComparator { settings },
+        ),
+        request_sender,
+        prev: None,
+        reader_join_handle,
+    })
+}
+/// The struct on the reader thread representing an input file
+struct ReaderFile<M: MergeInput> {
+    file: M,
+    sender: SyncSender<Chunk>,
+    carry_over: Vec<u8>,
+}
+
+/// The function running on the reader thread.
+fn reader(
+    recycled_receiver: Receiver<(usize, RecycledChunk)>,
+    files: &mut [Option<ReaderFile<impl MergeInput>>],
+    settings: &GlobalSettings,
+    separator: u8,
+) -> UResult<()> {
+    for (file_idx, recycled_chunk) in recycled_receiver.iter() {
+        if let Some(ReaderFile {
+            file,
+            sender,
+            carry_over,
+        }) = &mut files[file_idx]
+        {
+            let should_continue = chunks::read(
+                sender,
+                recycled_chunk,
+                None,
+                carry_over,
+                file.as_read(),
+                &mut iter::empty(),
+                separator,
+                settings,
+            )?;
+            if !should_continue {
+                // Remove the file from the list by replacing it with `None`.
+                let ReaderFile { file, .. } = files[file_idx].take().unwrap();
+                // Depending on the kind of the `MergeInput`, this may delete the file:
+                file.finished_reading()?;
+            }
+        }
+    }
+    Ok(())
+}
+/// The struct on the main thread representing an input file
+pub struct MergeableFile {
+    current_chunk: Rc<Chunk>,
+    line_idx: usize,
+    receiver: Receiver<Chunk>,
+    file_number: usize,
+}
+
+/// A struct to keep track of the previous line we encountered.
+///
+/// This is required for deduplication purposes.
+struct PreviousLine {
+    chunk: Rc<Chunk>,
+    line_idx: usize,
+    file_number: usize,
+}
+
+/// Merges files together. This is **not** an iterator because of lifetime problems.
+pub struct FileMerger<'a> {
+    heap: binary_heap_plus::BinaryHeap<MergeableFile, FileComparator<'a>>,
+    request_sender: Sender<(usize, RecycledChunk)>,
+    prev: Option<PreviousLine>,
+    reader_join_handle: JoinHandle<UResult<()>>,
+}
+
+impl<'a> FileMerger<'a> {
+    /// Write the merged contents to the output file.
+    pub fn write_all(self, settings: &GlobalSettings, output: Output) -> UResult<()> {
+        let mut out = output.into_write();
+        self.write_all_to(settings, &mut out)
+    }
+
+    pub fn write_all_to(mut self, settings: &GlobalSettings, out: &mut impl Write) -> UResult<()> {
+        while self.write_next(settings, out) {}
+        drop(self.request_sender);
+        self.reader_join_handle.join().unwrap()
+    }
+
+    fn write_next(&mut self, settings: &GlobalSettings, out: &mut impl Write) -> bool {
+        if let Some(file) = self.heap.peek() {
+            let prev = self.prev.replace(PreviousLine {
+                chunk: file.current_chunk.clone(),
+                line_idx: file.line_idx,
+                file_number: file.file_number,
+            });
+
+            file.current_chunk.with_contents(|contents| {
+                let current_line = &contents.lines[file.line_idx];
+                if settings.unique {
+                    if let Some(prev) = &prev {
+                        let cmp = compare_by(
+                            &prev.chunk.lines()[prev.line_idx],
+                            current_line,
+                            settings,
+                            prev.chunk.line_data(),
+                            file.current_chunk.line_data(),
+                        );
+                        if cmp == Ordering::Equal {
+                            return;
+                        }
+                    }
+                }
+                current_line.print(out, settings);
+            });
+
+            let was_last_line_for_file = file.current_chunk.lines().len() == file.line_idx + 1;
+
+            if was_last_line_for_file {
+                if let Ok(next_chunk) = file.receiver.recv() {
+                    let mut file = self.heap.peek_mut().unwrap();
+                    file.current_chunk = Rc::new(next_chunk);
+                    file.line_idx = 0;
+                } else {
+                    self.heap.pop();
+                }
+            } else {
+                // This will cause the comparison to use a different line and the heap to readjust.
+                self.heap.peek_mut().unwrap().line_idx += 1;
+            }
+
+            if let Some(prev) = prev {
+                if let Ok(prev_chunk) = Rc::try_unwrap(prev.chunk) {
+                    // If nothing is referencing the previous chunk anymore, this means that the previous line
+                    // was the last line of the chunk. We can recycle the chunk.
+                    self.request_sender
+                        .send((prev.file_number, prev_chunk.recycle()))
+                        .ok();
+                }
+            }
+        }
+        !self.heap.is_empty()
+    }
+}
+
+/// Compares files by their current line.
+struct FileComparator<'a> {
+    settings: &'a GlobalSettings,
+}
+
+impl<'a> Compare<MergeableFile> for FileComparator<'a> {
+    fn compare(&self, a: &MergeableFile, b: &MergeableFile) -> Ordering {
+        let mut cmp = compare_by(
+            &a.current_chunk.lines()[a.line_idx],
+            &b.current_chunk.lines()[b.line_idx],
+            self.settings,
+            a.current_chunk.line_data(),
+            b.current_chunk.line_data(),
+        );
+        if cmp == Ordering::Equal {
+            // To make sorting stable, we need to consider the file number as well,
+            // as lines from a file with a lower number are to be considered "earlier".
+            cmp = a.file_number.cmp(&b.file_number);
+        }
+        // BinaryHeap is a max heap. We use it as a min heap, so we need to reverse the ordering.
+        cmp.reverse()
+    }
+}
+
+// Wait for the child to exit and check its exit code.
+fn check_child_success(mut child: Child, program: &str) -> UResult<()> {
+    if !matches!(
+        child.wait().map(|e| e.code()),
+        Ok(Some(0)) | Ok(None) | Err(_)
+    ) {
+        Err(SortError::CompressProgTerminatedAbnormally {
+            prog: program.to_owned(),
+        }
+        .into())
+    } else {
+        Ok(())
+    }
+}
+
+/// A temporary file that can be written to.
+pub trait WriteableTmpFile: Sized {
+    type Closed: ClosedTmpFile;
+    type InnerWrite: Write;
+    fn create(file: (File, PathBuf), compress_prog: Option<&str>) -> UResult<Self>;
+    /// Closes the temporary file.
+    fn finished_writing(self) -> UResult<Self::Closed>;
+    fn as_write(&mut self) -> &mut Self::InnerWrite;
+}
+/// A temporary file that is (temporarily) closed, but can be reopened.
+pub trait ClosedTmpFile {
+    type Reopened: MergeInput;
+    /// Reopens the temporary file.
+    fn reopen(self) -> UResult<Self::Reopened>;
+}
+/// A pre-sorted input for merging.
+pub trait MergeInput: Send {
+    type InnerRead: Read;
+    /// Cleans this `MergeInput` up.
+    /// Implementations may delete the backing file.
+    fn finished_reading(self) -> UResult<()>;
+    fn as_read(&mut self) -> &mut Self::InnerRead;
+}
+
+pub struct WriteablePlainTmpFile {
+    path: PathBuf,
+    file: BufWriter<File>,
+}
+pub struct ClosedPlainTmpFile {
+    path: PathBuf,
+}
+pub struct PlainTmpMergeInput {
+    path: PathBuf,
+    file: File,
+}
+impl WriteableTmpFile for WriteablePlainTmpFile {
+    type Closed = ClosedPlainTmpFile;
+    type InnerWrite = BufWriter<File>;
+
+    fn create((file, path): (File, PathBuf), _: Option<&str>) -> UResult<Self> {
+        Ok(WriteablePlainTmpFile {
+            file: BufWriter::new(file),
+            path,
+        })
+    }
+
+    fn finished_writing(self) -> UResult<Self::Closed> {
+        Ok(ClosedPlainTmpFile { path: self.path })
+    }
+
+    fn as_write(&mut self) -> &mut Self::InnerWrite {
+        &mut self.file
+    }
+}
+impl ClosedTmpFile for ClosedPlainTmpFile {
+    type Reopened = PlainTmpMergeInput;
+    fn reopen(self) -> UResult<Self::Reopened> {
+        Ok(PlainTmpMergeInput {
+            file: File::open(&self.path).map_err(|error| SortError::OpenTmpFileFailed { error })?,
+            path: self.path,
+        })
+    }
+}
+impl MergeInput for PlainTmpMergeInput {
+    type InnerRead = File;
+
+    fn finished_reading(self) -> UResult<()> {
+        // we ignore failures to delete the temporary file,
+        // because there is a race at the end of the execution and the whole
+        // temporary directory might already be gone.
+        let _ = fs::remove_file(self.path);
+        Ok(())
+    }
+
+    fn as_read(&mut self) -> &mut Self::InnerRead {
+        &mut self.file
+    }
+}
+
+pub struct WriteableCompressedTmpFile {
+    path: PathBuf,
+    compress_prog: String,
+    child: Child,
+    child_stdin: BufWriter<ChildStdin>,
+}
+pub struct ClosedCompressedTmpFile {
+    path: PathBuf,
+    compress_prog: String,
+}
+pub struct CompressedTmpMergeInput {
+    path: PathBuf,
+    compress_prog: String,
+    child: Child,
+    child_stdout: ChildStdout,
+}
+impl WriteableTmpFile for WriteableCompressedTmpFile {
+    type Closed = ClosedCompressedTmpFile;
+    type InnerWrite = BufWriter<ChildStdin>;
+
+    fn create((file, path): (File, PathBuf), compress_prog: Option<&str>) -> UResult<Self> {
+        let compress_prog = compress_prog.unwrap();
+        let mut command = Command::new(compress_prog);
+        command.stdin(Stdio::piped()).stdout(file);
+        let mut child = command
+            .spawn()
+            .map_err(|err| SortError::CompressProgExecutionFailed {
+                code: err.raw_os_error().unwrap(),
+            })?;
+        let child_stdin = child.stdin.take().unwrap();
+        Ok(WriteableCompressedTmpFile {
+            path,
+            compress_prog: compress_prog.to_owned(),
+            child,
+            child_stdin: BufWriter::new(child_stdin),
+        })
+    }
+
+    fn finished_writing(self) -> UResult<Self::Closed> {
+        drop(self.child_stdin);
+        check_child_success(self.child, &self.compress_prog)?;
+        Ok(ClosedCompressedTmpFile {
+            path: self.path,
+            compress_prog: self.compress_prog,
+        })
+    }
+
+    fn as_write(&mut self) -> &mut Self::InnerWrite {
+        &mut self.child_stdin
+    }
+}
+impl ClosedTmpFile for ClosedCompressedTmpFile {
+    type Reopened = CompressedTmpMergeInput;
+
+    fn reopen(self) -> UResult<Self::Reopened> {
+        let mut command = Command::new(&self.compress_prog);
+        let file = File::open(&self.path).unwrap();
+        command.stdin(file).stdout(Stdio::piped()).arg("-d");
+        let mut child = command
+            .spawn()
+            .map_err(|err| SortError::CompressProgExecutionFailed {
+                code: err.raw_os_error().unwrap(),
+            })?;
+        let child_stdout = child.stdout.take().unwrap();
+        Ok(CompressedTmpMergeInput {
+            path: self.path,
+            compress_prog: self.compress_prog,
+            child,
+            child_stdout,
+        })
+    }
+}
+impl MergeInput for CompressedTmpMergeInput {
+    type InnerRead = ChildStdout;
+
+    fn finished_reading(self) -> UResult<()> {
+        drop(self.child_stdout);
+        check_child_success(self.child, &self.compress_prog)?;
+        let _ = fs::remove_file(self.path);
+        Ok(())
+    }
+
+    fn as_read(&mut self) -> &mut Self::InnerRead {
+        &mut self.child_stdout
+    }
+}
+
+pub struct PlainMergeInput<R: Read + Send> {
+    inner: R,
+}
+impl<R: Read + Send> MergeInput for PlainMergeInput<R> {
+    type InnerRead = R;
+    fn finished_reading(self) -> UResult<()> {
+        Ok(())
+    }
+    fn as_read(&mut self) -> &mut Self::InnerRead {
+        &mut self.inner
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/numeric_str_cmp.rs.html b/src/uu_sort/numeric_str_cmp.rs.html new file mode 100644 index 000000000..cfdf0d529 --- /dev/null +++ b/src/uu_sort/numeric_str_cmp.rs.html @@ -0,0 +1,1015 @@ +numeric_str_cmp.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Debertol <michael.debertol..AT..gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+//! Fast comparison for strings representing a base 10 number without precision loss.
+//!
+//! To be able to short-circuit when comparing, [NumInfo] must be passed along with each number
+//! to [numeric_str_cmp]. [NumInfo] is generally obtained by calling [NumInfo::parse] and should be cached.
+//! It is allowed to arbitrarily modify the exponent afterwards, which is equivalent to shifting the decimal point.
+//!
+//! More specifically, exponent can be understood so that the original number is in (1..10)*10^exponent.
+//! From that follows the constraints of this algorithm: It is able to compare numbers in ±(1*10^[i64::MIN]..10*10^[i64::MAX]).
+
+use std::{cmp::Ordering, ops::Range};
+
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
+enum Sign {
+    Negative,
+    Positive,
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub struct NumInfo {
+    exponent: i64,
+    sign: Sign,
+}
+#[derive(Debug, PartialEq, Clone)]
+pub struct NumInfoParseSettings {
+    pub accept_si_units: bool,
+    pub thousands_separator: Option<char>,
+    pub decimal_pt: Option<char>,
+}
+
+impl Default for NumInfoParseSettings {
+    fn default() -> Self {
+        Self {
+            accept_si_units: false,
+            thousands_separator: None,
+            decimal_pt: Some('.'),
+        }
+    }
+}
+
+impl NumInfo {
+    /// Parse NumInfo for this number.
+    /// Also returns the range of num that should be passed to numeric_str_cmp later.
+    ///
+    /// Leading zeros will be excluded from the returned range. If the number consists of only zeros,
+    /// an empty range (idx..idx) is returned so that idx is the char after the last zero.
+    /// If the input is not a number (which has to be treated as zero), the returned empty range
+    /// will be 0..0.
+    pub fn parse(num: &str, parse_settings: NumInfoParseSettings) -> (Self, Range<usize>) {
+        let mut exponent = -1;
+        let mut had_decimal_pt = false;
+        let mut had_digit = false;
+        let mut start = None;
+        let mut sign = Sign::Positive;
+
+        let mut first_char = true;
+
+        for (idx, char) in num.char_indices() {
+            if first_char && char.is_whitespace() {
+                continue;
+            }
+
+            if first_char && char == '-' {
+                sign = Sign::Negative;
+                first_char = false;
+                continue;
+            }
+            first_char = false;
+
+            if matches!(
+                parse_settings.thousands_separator,
+                Some(c) if c == char
+            ) {
+                continue;
+            }
+
+            if Self::is_invalid_char(char, &mut had_decimal_pt, &parse_settings) {
+                return if let Some(start) = start {
+                    let has_si_unit = parse_settings.accept_si_units
+                        && matches!(char, 'K' | 'k' | 'M' | 'G' | 'T' | 'P' | 'E' | 'Z' | 'Y');
+                    (
+                        NumInfo { exponent, sign },
+                        start..if has_si_unit { idx + 1 } else { idx },
+                    )
+                } else {
+                    (
+                        NumInfo {
+                            sign: Sign::Positive,
+                            exponent: 0,
+                        },
+                        if had_digit {
+                            // In this case there were only zeroes.
+                            // For debug output to work properly, we have to match the character after the last zero.
+                            idx..idx
+                        } else {
+                            // This was no number at all.
+                            // For debug output to work properly, we have to match 0..0.
+                            0..0
+                        },
+                    )
+                };
+            }
+            if Some(char) == parse_settings.decimal_pt {
+                continue;
+            }
+            had_digit = true;
+            if start.is_none() && char == '0' {
+                if had_decimal_pt {
+                    // We're parsing a number whose first nonzero digit is after the decimal point.
+                    exponent -= 1;
+                } else {
+                    // Skip leading zeroes
+                    continue;
+                }
+            }
+            if !had_decimal_pt {
+                exponent += 1;
+            }
+            if start.is_none() && char != '0' {
+                start = Some(idx);
+            }
+        }
+        if let Some(start) = start {
+            (NumInfo { exponent, sign }, start..num.len())
+        } else {
+            (
+                NumInfo {
+                    sign: Sign::Positive,
+                    exponent: 0,
+                },
+                if had_digit {
+                    // In this case there were only zeroes.
+                    // For debug output to work properly, we have to claim to match the end of the number.
+                    num.len()..num.len()
+                } else {
+                    // This was no number at all.
+                    // For debug output to work properly, we have to claim to match the start of the number.
+                    0..0
+                },
+            )
+        }
+    }
+
+    fn is_invalid_char(
+        c: char,
+        had_decimal_pt: &mut bool,
+        parse_settings: &NumInfoParseSettings,
+    ) -> bool {
+        if Some(c) == parse_settings.decimal_pt {
+            if *had_decimal_pt {
+                // this is a decimal pt but we already had one, so it is invalid
+                true
+            } else {
+                *had_decimal_pt = true;
+                false
+            }
+        } else {
+            !c.is_ascii_digit()
+        }
+    }
+}
+
+fn get_unit(unit: Option<char>) -> u8 {
+    if let Some(unit) = unit {
+        match unit {
+            'K' | 'k' => 1,
+            'M' => 2,
+            'G' => 3,
+            'T' => 4,
+            'P' => 5,
+            'E' => 6,
+            'Z' => 7,
+            'Y' => 8,
+            _ => 0,
+        }
+    } else {
+        0
+    }
+}
+
+/// Compare two numbers according to the rules of human numeric comparison.
+/// The SI-Unit takes precedence over the actual value (i.e. 2000M < 1G).
+pub fn human_numeric_str_cmp(
+    (a, a_info): (&str, &NumInfo),
+    (b, b_info): (&str, &NumInfo),
+) -> Ordering {
+    // 1. Sign
+    if a_info.sign != b_info.sign {
+        return a_info.sign.cmp(&b_info.sign);
+    }
+    // 2. Unit
+    let a_unit = get_unit(a.chars().next_back());
+    let b_unit = get_unit(b.chars().next_back());
+    let ordering = a_unit.cmp(&b_unit);
+    if ordering != Ordering::Equal {
+        if a_info.sign == Sign::Negative {
+            ordering.reverse()
+        } else {
+            ordering
+        }
+    } else {
+        // 3. Number
+        numeric_str_cmp((a, a_info), (b, b_info))
+    }
+}
+
+/// Compare two numbers as strings without parsing them as a number first. This should be more performant and can handle numbers more precisely.
+/// NumInfo is needed to provide a fast path for most numbers.
+#[inline(always)]
+pub fn numeric_str_cmp((a, a_info): (&str, &NumInfo), (b, b_info): (&str, &NumInfo)) -> Ordering {
+    // check for a difference in the sign
+    if a_info.sign != b_info.sign {
+        return a_info.sign.cmp(&b_info.sign);
+    }
+
+    // check for a difference in the exponent
+    let ordering = if a_info.exponent != b_info.exponent && !a.is_empty() && !b.is_empty() {
+        a_info.exponent.cmp(&b_info.exponent)
+    } else {
+        // walk the characters from the front until we find a difference
+        let mut a_chars = a.chars().filter(|c| c.is_ascii_digit());
+        let mut b_chars = b.chars().filter(|c| c.is_ascii_digit());
+        loop {
+            let a_next = a_chars.next();
+            let b_next = b_chars.next();
+            match (a_next, b_next) {
+                (None, None) => break Ordering::Equal,
+                (Some(c), None) => {
+                    break if c == '0' && a_chars.all(|c| c == '0') {
+                        Ordering::Equal
+                    } else {
+                        Ordering::Greater
+                    }
+                }
+                (None, Some(c)) => {
+                    break if c == '0' && b_chars.all(|c| c == '0') {
+                        Ordering::Equal
+                    } else {
+                        Ordering::Less
+                    }
+                }
+                (Some(a_char), Some(b_char)) => {
+                    let ord = a_char.cmp(&b_char);
+                    if ord != Ordering::Equal {
+                        break ord;
+                    }
+                }
+            }
+        }
+    };
+
+    if a_info.sign == Sign::Negative {
+        ordering.reverse()
+    } else {
+        ordering
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn parses_exp() {
+        let n = "1";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Positive
+                },
+                0..1
+            )
+        );
+        let n = "100";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 2,
+                    sign: Sign::Positive
+                },
+                0..3
+            )
+        );
+        let n = "1,000";
+        assert_eq!(
+            NumInfo::parse(
+                n,
+                NumInfoParseSettings {
+                    thousands_separator: Some(','),
+                    ..Default::default()
+                }
+            ),
+            (
+                NumInfo {
+                    exponent: 3,
+                    sign: Sign::Positive
+                },
+                0..5
+            )
+        );
+        let n = "1,000";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Positive
+                },
+                0..1
+            )
+        );
+        let n = "1000.00";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 3,
+                    sign: Sign::Positive
+                },
+                0..7
+            )
+        );
+    }
+    #[test]
+    fn parses_negative_exp() {
+        let n = "0.00005";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: -5,
+                    sign: Sign::Positive
+                },
+                6..7
+            )
+        );
+        let n = "00000.00005";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: -5,
+                    sign: Sign::Positive
+                },
+                10..11
+            )
+        );
+    }
+
+    #[test]
+    fn parses_sign() {
+        let n = "5";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Positive
+                },
+                0..1
+            )
+        );
+        let n = "-5";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Negative
+                },
+                1..2
+            )
+        );
+        let n = "    -5";
+        assert_eq!(
+            NumInfo::parse(n, Default::default()),
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Negative
+                },
+                5..6
+            )
+        );
+    }
+
+    fn test_helper(a: &str, b: &str, expected: Ordering) {
+        let (a_info, a_range) = NumInfo::parse(a, Default::default());
+        let (b_info, b_range) = NumInfo::parse(b, Default::default());
+        let ordering = numeric_str_cmp(
+            (&a[a_range.to_owned()], &a_info),
+            (&b[b_range.to_owned()], &b_info),
+        );
+        assert_eq!(ordering, expected);
+        let ordering = numeric_str_cmp((&b[b_range], &b_info), (&a[a_range], &a_info));
+        assert_eq!(ordering, expected.reverse());
+    }
+    #[test]
+    fn test_single_digit() {
+        test_helper("1", "2", Ordering::Less);
+        test_helper("0", "0", Ordering::Equal);
+    }
+    #[test]
+    fn test_minus() {
+        test_helper("-1", "-2", Ordering::Greater);
+        test_helper("-0", "-0", Ordering::Equal);
+    }
+    #[test]
+    fn test_different_len() {
+        test_helper("-20", "-100", Ordering::Greater);
+        test_helper("10.0", "2.000000", Ordering::Greater);
+    }
+    #[test]
+    fn test_decimal_digits() {
+        test_helper("20.1", "20.2", Ordering::Less);
+        test_helper("20.1", "20.15", Ordering::Less);
+        test_helper("-20.1", "+20.15", Ordering::Less);
+        test_helper("-20.1", "-20", Ordering::Less);
+    }
+    #[test]
+    fn test_trailing_zeroes() {
+        test_helper("20.00000", "20.1", Ordering::Less);
+        test_helper("20.00000", "20.0", Ordering::Equal);
+    }
+    #[test]
+    fn test_invalid_digits() {
+        test_helper("foo", "bar", Ordering::Equal);
+        test_helper("20.1", "a", Ordering::Greater);
+        test_helper("-20.1", "a", Ordering::Less);
+        test_helper("a", "0.15", Ordering::Less);
+    }
+    #[test]
+    fn test_multiple_decimal_pts() {
+        test_helper("10.0.0", "50.0.0", Ordering::Less);
+        test_helper("0.1.", "0.2.0", Ordering::Less);
+        test_helper("1.1.", "0", Ordering::Greater);
+        test_helper("1.1.", "-0", Ordering::Greater);
+    }
+    #[test]
+    fn test_leading_decimal_pts() {
+        test_helper(".0", ".0", Ordering::Equal);
+        test_helper(".1", ".0", Ordering::Greater);
+        test_helper(".02", "0", Ordering::Greater);
+    }
+    #[test]
+    fn test_leading_zeroes() {
+        test_helper("000000.0", ".0", Ordering::Equal);
+        test_helper("0.1", "0000000000000.0", Ordering::Greater);
+        test_helper("-01", "-2", Ordering::Greater);
+    }
+
+    #[test]
+    fn minus_zero() {
+        // This matches GNU sort behavior.
+        test_helper("-0", "0", Ordering::Equal);
+        test_helper("-0x", "0", Ordering::Equal);
+    }
+    #[test]
+    fn double_minus() {
+        test_helper("--1", "0", Ordering::Equal);
+    }
+    #[test]
+    fn single_minus() {
+        let info = NumInfo::parse("-", Default::default());
+        assert_eq!(
+            info,
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Positive
+                },
+                0..0
+            )
+        );
+    }
+    #[test]
+    fn invalid_with_unit() {
+        let info = NumInfo::parse(
+            "-K",
+            NumInfoParseSettings {
+                accept_si_units: true,
+                ..Default::default()
+            },
+        );
+        assert_eq!(
+            info,
+            (
+                NumInfo {
+                    exponent: 0,
+                    sign: Sign::Positive
+                },
+                0..0
+            )
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/sort.rs.html b/src/uu_sort/sort.rs.html new file mode 100644 index 000000000..af1da4037 --- /dev/null +++ b/src/uu_sort/sort.rs.html @@ -0,0 +1,3979 @@ +sort.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Yin <mikeyin@mikeyin.org>
+//  * (c) Robert Swinford <robert.swinford..AT..gmail.com>
+//  * (c) Michael Debertol <michael.debertol..AT..gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// Although these links don't always seem to describe reality, check out the POSIX and GNU specs:
+// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sort.html
+// https://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html
+
+// spell-checker:ignore (misc) HFKJFK Mbdfhn
+
+#[macro_use]
+extern crate uucore;
+
+mod check;
+mod chunks;
+mod custom_str_cmp;
+mod ext_sort;
+mod merge;
+mod numeric_str_cmp;
+mod tmp_dir;
+
+use chunks::LineData;
+use clap::{crate_version, App, Arg};
+use custom_str_cmp::custom_str_cmp;
+use ext_sort::ext_sort;
+use fnv::FnvHasher;
+use numeric_str_cmp::{human_numeric_str_cmp, numeric_str_cmp, NumInfo, NumInfoParseSettings};
+use rand::{thread_rng, Rng};
+use rayon::prelude::*;
+use std::cmp::Ordering;
+use std::env;
+use std::error::Error;
+use std::ffi::{OsStr, OsString};
+use std::fmt::Display;
+use std::fs::{File, OpenOptions};
+use std::hash::{Hash, Hasher};
+use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
+use std::ops::Range;
+use std::path::Path;
+use std::path::PathBuf;
+use std::str::Utf8Error;
+use unicode_width::UnicodeWidthStr;
+use uucore::error::{set_exit_code, UError, UResult, USimpleError, UUsageError};
+use uucore::parse_size::{parse_size, ParseSizeError};
+use uucore::version_cmp::version_cmp;
+use uucore::InvalidEncodingHandling;
+
+use crate::tmp_dir::TmpDirWrapper;
+
+const ABOUT: &str = "Display sorted concatenation of all FILE(s).";
+
+const LONG_HELP_KEYS: &str = "The key format is FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS].
+
+Fields by default are separated by the first whitespace after a non-whitespace character. Use -t to specify a custom separator.
+In the default case, whitespace is appended at the beginning of each field. Custom separators however are not included in fields.
+
+FIELD and CHAR both start at 1 (i.e. they are 1-indexed). If there is no end specified after a comma, the end will be the end of the line.
+If CHAR is set 0, it means the end of the field. CHAR defaults to 1 for the start position and to 0 for the end position.
+
+Valid options are: MbdfhnRrV. They override the global options for this key.";
+
+mod options {
+    pub mod modes {
+        pub const SORT: &str = "sort";
+
+        pub const HUMAN_NUMERIC: &str = "human-numeric-sort";
+        pub const MONTH: &str = "month-sort";
+        pub const NUMERIC: &str = "numeric-sort";
+        pub const GENERAL_NUMERIC: &str = "general-numeric-sort";
+        pub const VERSION: &str = "version-sort";
+        pub const RANDOM: &str = "random-sort";
+
+        pub const ALL_SORT_MODES: [&str; 6] = [
+            GENERAL_NUMERIC,
+            HUMAN_NUMERIC,
+            MONTH,
+            NUMERIC,
+            VERSION,
+            RANDOM,
+        ];
+    }
+
+    pub mod check {
+        pub const CHECK: &str = "check";
+        pub const CHECK_SILENT: &str = "check-silent";
+        pub const SILENT: &str = "silent";
+        pub const QUIET: &str = "quiet";
+        pub const DIAGNOSE_FIRST: &str = "diagnose-first";
+    }
+
+    pub const DICTIONARY_ORDER: &str = "dictionary-order";
+    pub const MERGE: &str = "merge";
+    pub const DEBUG: &str = "debug";
+    pub const IGNORE_CASE: &str = "ignore-case";
+    pub const IGNORE_LEADING_BLANKS: &str = "ignore-leading-blanks";
+    pub const IGNORE_NONPRINTING: &str = "ignore-nonprinting";
+    pub const OUTPUT: &str = "output";
+    pub const REVERSE: &str = "reverse";
+    pub const STABLE: &str = "stable";
+    pub const UNIQUE: &str = "unique";
+    pub const KEY: &str = "key";
+    pub const SEPARATOR: &str = "field-separator";
+    pub const ZERO_TERMINATED: &str = "zero-terminated";
+    pub const PARALLEL: &str = "parallel";
+    pub const FILES0_FROM: &str = "files0-from";
+    pub const BUF_SIZE: &str = "buffer-size";
+    pub const TMP_DIR: &str = "temporary-directory";
+    pub const COMPRESS_PROG: &str = "compress-program";
+    pub const BATCH_SIZE: &str = "batch-size";
+
+    pub const FILES: &str = "files";
+}
+
+const DECIMAL_PT: char = '.';
+
+const NEGATIVE: char = '-';
+const POSITIVE: char = '+';
+
+// Choosing a higher buffer size does not result in performance improvements
+// (at least not on my machine). TODO: In the future, we should also take the amount of
+// available memory into consideration, instead of relying on this constant only.
+const DEFAULT_BUF_SIZE: usize = 1_000_000_000; // 1 GB
+
+#[derive(Debug)]
+enum SortError {
+    Disorder {
+        file: OsString,
+        line_number: usize,
+        line: String,
+        silent: bool,
+    },
+    OpenFailed {
+        path: String,
+        error: std::io::Error,
+    },
+    ReadFailed {
+        path: String,
+        error: std::io::Error,
+    },
+    ParseKeyError {
+        key: String,
+        msg: String,
+    },
+    OpenTmpFileFailed {
+        error: std::io::Error,
+    },
+    CompressProgExecutionFailed {
+        code: i32,
+    },
+    CompressProgTerminatedAbnormally {
+        prog: String,
+    },
+    TmpDirCreationFailed,
+    Uft8Error {
+        error: Utf8Error,
+    },
+}
+
+impl Error for SortError {}
+
+impl UError for SortError {
+    fn code(&self) -> i32 {
+        match self {
+            SortError::Disorder { .. } => 1,
+            _ => 2,
+        }
+    }
+
+    fn usage(&self) -> bool {
+        false
+    }
+}
+
+impl Display for SortError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            SortError::Disorder {
+                file,
+                line_number,
+                line,
+                silent,
+            } => {
+                if !silent {
+                    write!(
+                        f,
+                        "{}:{}: disorder: {}",
+                        file.to_string_lossy(),
+                        line_number,
+                        line
+                    )
+                } else {
+                    Ok(())
+                }
+            }
+            SortError::OpenFailed { path, error } => write!(
+                f,
+                "open failed: {}: {}",
+                path,
+                strip_errno(&error.to_string())
+            ),
+            SortError::ParseKeyError { key, msg } => {
+                write!(f, "failed to parse key `{}`: {}", key, msg)
+            }
+            SortError::ReadFailed { path, error } => write!(
+                f,
+                "cannot read: {}: {}",
+                path,
+                strip_errno(&error.to_string())
+            ),
+            SortError::OpenTmpFileFailed { error } => {
+                write!(
+                    f,
+                    "failed to open temporary file: {}",
+                    strip_errno(&error.to_string())
+                )
+            }
+            SortError::CompressProgExecutionFailed { code } => {
+                write!(f, "couldn't execute compress program: errno {}", code)
+            }
+            SortError::CompressProgTerminatedAbnormally { prog } => {
+                write!(f, "'{}' terminated abnormally", prog)
+            }
+            SortError::TmpDirCreationFailed => write!(f, "could not create temporary directory"),
+            SortError::Uft8Error { error } => write!(f, "{}", error),
+        }
+    }
+}
+
+#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug)]
+enum SortMode {
+    Numeric,
+    HumanNumeric,
+    GeneralNumeric,
+    Month,
+    Version,
+    Random,
+    Default,
+}
+
+impl SortMode {
+    fn get_short_name(&self) -> Option<char> {
+        match self {
+            SortMode::Numeric => Some('n'),
+            SortMode::HumanNumeric => Some('h'),
+            SortMode::GeneralNumeric => Some('g'),
+            SortMode::Month => Some('M'),
+            SortMode::Version => Some('V'),
+            SortMode::Random => Some('R'),
+            SortMode::Default => None,
+        }
+    }
+}
+
+pub struct Output {
+    file: Option<(String, File)>,
+}
+
+impl Output {
+    fn new(name: Option<&str>) -> UResult<Self> {
+        let file = if let Some(name) = name {
+            // This is different from `File::create()` because we don't truncate the output yet.
+            // This allows using the output file as an input file.
+            let file = OpenOptions::new()
+                .write(true)
+                .create(true)
+                .open(name)
+                .map_err(|e| SortError::OpenFailed {
+                    path: name.to_owned(),
+                    error: e,
+                })?;
+            Some((name.to_owned(), file))
+        } else {
+            None
+        };
+        Ok(Self { file })
+    }
+
+    fn into_write(self) -> BufWriter<Box<dyn Write>> {
+        BufWriter::new(match self.file {
+            Some((_name, file)) => {
+                // truncate the file
+                let _ = file.set_len(0);
+                Box::new(file)
+            }
+            None => Box::new(stdout()),
+        })
+    }
+
+    fn as_output_name(&self) -> Option<&str> {
+        match &self.file {
+            Some((name, _file)) => Some(name),
+            None => None,
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct GlobalSettings {
+    mode: SortMode,
+    debug: bool,
+    ignore_leading_blanks: bool,
+    ignore_case: bool,
+    dictionary_order: bool,
+    ignore_non_printing: bool,
+    merge: bool,
+    reverse: bool,
+    stable: bool,
+    unique: bool,
+    check: bool,
+    check_silent: bool,
+    salt: Option<[u8; 16]>,
+    selectors: Vec<FieldSelector>,
+    separator: Option<char>,
+    threads: String,
+    zero_terminated: bool,
+    buffer_size: usize,
+    compress_prog: Option<String>,
+    merge_batch_size: usize,
+    precomputed: Precomputed,
+}
+
+/// Data needed for sorting. Should be computed once before starting to sort
+/// by calling `GlobalSettings::init_precomputed`.
+#[derive(Clone, Debug)]
+struct Precomputed {
+    needs_tokens: bool,
+    num_infos_per_line: usize,
+    floats_per_line: usize,
+    selections_per_line: usize,
+}
+
+impl GlobalSettings {
+    /// Parse a SIZE string into a number of bytes.
+    /// A size string comprises an integer and an optional unit.
+    /// The unit may be k, K, m, M, g, G, t, T, P, E, Z, Y (powers of 1024), or b which is 1.
+    /// Default is K.
+    fn parse_byte_count(input: &str) -> Result<usize, ParseSizeError> {
+        // GNU sort (8.32)   valid: 1b,        k, K, m, M, g, G, t, T, P, E, Z, Y
+        // GNU sort (8.32) invalid:  b, B, 1B,                         p, e, z, y
+        const ALLOW_LIST: &[char] = &[
+            'b', 'k', 'K', 'm', 'M', 'g', 'G', 't', 'T', 'P', 'E', 'Z', 'Y',
+        ];
+        let mut size_string = input.trim().to_string();
+
+        if size_string.ends_with(|c: char| ALLOW_LIST.contains(&c) || c.is_digit(10)) {
+            // b 1, K 1024 (default)
+            if size_string.ends_with(|c: char| c.is_digit(10)) {
+                size_string.push('K');
+            } else if size_string.ends_with('b') {
+                size_string.pop();
+            }
+            parse_size(&size_string)
+        } else {
+            Err(ParseSizeError::ParseFailure("invalid suffix".to_string()))
+        }
+    }
+
+    /// Precompute some data needed for sorting.
+    /// This function **must** be called before starting to sort, and `GlobalSettings` may not be altered
+    /// afterwards.
+    fn init_precomputed(&mut self) {
+        self.precomputed.needs_tokens = self.selectors.iter().any(|s| s.needs_tokens);
+        self.precomputed.selections_per_line =
+            self.selectors.iter().filter(|s| s.needs_selection).count();
+        self.precomputed.num_infos_per_line = self
+            .selectors
+            .iter()
+            .filter(|s| matches!(s.settings.mode, SortMode::Numeric | SortMode::HumanNumeric))
+            .count();
+        self.precomputed.floats_per_line = self
+            .selectors
+            .iter()
+            .filter(|s| matches!(s.settings.mode, SortMode::GeneralNumeric))
+            .count();
+    }
+}
+
+impl Default for GlobalSettings {
+    fn default() -> GlobalSettings {
+        GlobalSettings {
+            mode: SortMode::Default,
+            debug: false,
+            ignore_leading_blanks: false,
+            ignore_case: false,
+            dictionary_order: false,
+            ignore_non_printing: false,
+            merge: false,
+            reverse: false,
+            stable: false,
+            unique: false,
+            check: false,
+            check_silent: false,
+            salt: None,
+            selectors: vec![],
+            separator: None,
+            threads: String::new(),
+            zero_terminated: false,
+            buffer_size: DEFAULT_BUF_SIZE,
+            compress_prog: None,
+            merge_batch_size: 32,
+            precomputed: Precomputed {
+                num_infos_per_line: 0,
+                floats_per_line: 0,
+                selections_per_line: 0,
+                needs_tokens: false,
+            },
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Debug)]
+struct KeySettings {
+    mode: SortMode,
+    ignore_blanks: bool,
+    ignore_case: bool,
+    dictionary_order: bool,
+    ignore_non_printing: bool,
+    reverse: bool,
+}
+
+impl KeySettings {
+    /// Checks if the supplied combination of `mode`, `ignore_non_printing` and `dictionary_order` is allowed.
+    fn check_compatibility(
+        mode: SortMode,
+        ignore_non_printing: bool,
+        dictionary_order: bool,
+    ) -> Result<(), String> {
+        if matches!(
+            mode,
+            SortMode::Numeric | SortMode::HumanNumeric | SortMode::GeneralNumeric | SortMode::Month
+        ) {
+            if dictionary_order {
+                return Err(format!(
+                    "options '-{}{}' are incompatible",
+                    'd',
+                    mode.get_short_name().unwrap()
+                ));
+            } else if ignore_non_printing {
+                return Err(format!(
+                    "options '-{}{}' are incompatible",
+                    'i',
+                    mode.get_short_name().unwrap()
+                ));
+            }
+        }
+        Ok(())
+    }
+
+    fn set_sort_mode(&mut self, mode: SortMode) -> Result<(), String> {
+        if self.mode != SortMode::Default {
+            return Err(format!(
+                "options '-{}{}' are incompatible",
+                self.mode.get_short_name().unwrap(),
+                mode.get_short_name().unwrap()
+            ));
+        }
+        Self::check_compatibility(mode, self.ignore_non_printing, self.dictionary_order)?;
+        self.mode = mode;
+        Ok(())
+    }
+
+    fn set_dictionary_order(&mut self) -> Result<(), String> {
+        Self::check_compatibility(self.mode, self.ignore_non_printing, true)?;
+        self.dictionary_order = true;
+        Ok(())
+    }
+
+    fn set_ignore_non_printing(&mut self) -> Result<(), String> {
+        Self::check_compatibility(self.mode, true, self.dictionary_order)?;
+        self.ignore_non_printing = true;
+        Ok(())
+    }
+}
+
+impl From<&GlobalSettings> for KeySettings {
+    fn from(settings: &GlobalSettings) -> Self {
+        Self {
+            mode: settings.mode,
+            ignore_blanks: settings.ignore_leading_blanks,
+            ignore_case: settings.ignore_case,
+            ignore_non_printing: settings.ignore_non_printing,
+            reverse: settings.reverse,
+            dictionary_order: settings.dictionary_order,
+        }
+    }
+}
+
+impl Default for KeySettings {
+    fn default() -> Self {
+        Self::from(&GlobalSettings::default())
+    }
+}
+enum Selection<'a> {
+    AsF64(GeneralF64ParseResult),
+    WithNumInfo(&'a str, NumInfo),
+    Str(&'a str),
+}
+
+type Field = Range<usize>;
+
+#[derive(Clone, Debug)]
+pub struct Line<'a> {
+    line: &'a str,
+    index: usize,
+}
+
+impl<'a> Line<'a> {
+    /// Creates a new `Line`.
+    ///
+    /// If additional data is needed for sorting it is added to `line_data`.
+    /// `token_buffer` allows to reuse the allocation for tokens.
+    fn create(
+        line: &'a str,
+        index: usize,
+        line_data: &mut LineData<'a>,
+        token_buffer: &mut Vec<Field>,
+        settings: &GlobalSettings,
+    ) -> Self {
+        token_buffer.clear();
+        if settings.precomputed.needs_tokens {
+            tokenize(line, settings.separator, token_buffer);
+        }
+        for (selector, selection) in settings
+            .selectors
+            .iter()
+            .map(|selector| (selector, selector.get_selection(line, token_buffer)))
+        {
+            match selection {
+                Selection::AsF64(parsed_float) => line_data.parsed_floats.push(parsed_float),
+                Selection::WithNumInfo(str, num_info) => {
+                    line_data.num_infos.push(num_info);
+                    line_data.selections.push(str);
+                }
+                Selection::Str(str) => {
+                    if selector.needs_selection {
+                        line_data.selections.push(str)
+                    }
+                }
+            }
+        }
+        Self { line, index }
+    }
+
+    fn print(&self, writer: &mut impl Write, settings: &GlobalSettings) {
+        if settings.zero_terminated && !settings.debug {
+            writer.write_all(self.line.as_bytes()).unwrap();
+            writer.write_all(b"\0").unwrap();
+        } else if !settings.debug {
+            writer.write_all(self.line.as_bytes()).unwrap();
+            writer.write_all(b"\n").unwrap();
+        } else {
+            self.print_debug(settings, writer).unwrap();
+        }
+    }
+
+    /// Writes indicators for the selections this line matched. The original line content is NOT expected
+    /// to be already printed.
+    fn print_debug(
+        &self,
+        settings: &GlobalSettings,
+        writer: &mut impl Write,
+    ) -> std::io::Result<()> {
+        // We do not consider this function performance critical, as debug output is only useful for small files,
+        // which are not a performance problem in any case. Therefore there aren't any special performance
+        // optimizations here.
+
+        let line = self.line.replace('\t', ">");
+        writeln!(writer, "{}", line)?;
+
+        let mut fields = vec![];
+        tokenize(self.line, settings.separator, &mut fields);
+        for selector in settings.selectors.iter() {
+            let mut selection = selector.get_range(self.line, Some(&fields));
+            match selector.settings.mode {
+                SortMode::Numeric | SortMode::HumanNumeric => {
+                    // find out which range is used for numeric comparisons
+                    let (_, num_range) = NumInfo::parse(
+                        &self.line[selection.clone()],
+                        NumInfoParseSettings {
+                            accept_si_units: selector.settings.mode == SortMode::HumanNumeric,
+                            ..Default::default()
+                        },
+                    );
+                    let initial_selection = selection.clone();
+
+                    // Shorten selection to num_range.
+                    selection.start += num_range.start;
+                    selection.end = selection.start + num_range.len();
+
+                    if num_range != (0..0) {
+                        // include a trailing si unit
+                        if selector.settings.mode == SortMode::HumanNumeric
+                            && self.line[selection.end..initial_selection.end]
+                                .starts_with(&['k', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'][..])
+                        {
+                            selection.end += 1;
+                        }
+
+                        // include leading zeroes, a leading minus or a leading decimal point
+                        while self.line[initial_selection.start..selection.start]
+                            .ends_with(&['-', '0', '.'][..])
+                        {
+                            selection.start -= 1;
+                        }
+                    } else {
+                        // This was not a valid number.
+                        // Report no match at the first non-whitespace character.
+                        let leading_whitespace = self.line[selection.clone()]
+                            .find(|c: char| !c.is_whitespace())
+                            .unwrap_or(0);
+                        selection.start += leading_whitespace;
+                        selection.end += leading_whitespace;
+                    }
+                }
+                SortMode::GeneralNumeric => {
+                    let initial_selection = &self.line[selection.clone()];
+
+                    let leading = get_leading_gen(initial_selection);
+
+                    // Shorten selection to leading.
+                    selection.start += leading.start;
+                    selection.end = selection.start + leading.len();
+                }
+                SortMode::Month => {
+                    let initial_selection = &self.line[selection.clone()];
+
+                    let mut month_chars = initial_selection
+                        .char_indices()
+                        .skip_while(|(_, c)| c.is_whitespace());
+
+                    let month = if month_parse(initial_selection) == Month::Unknown {
+                        // We failed to parse a month, which is equivalent to matching nothing.
+                        // Add the "no match for key" marker to the first non-whitespace character.
+                        let first_non_whitespace = month_chars.next();
+                        first_non_whitespace.map_or(
+                            initial_selection.len()..initial_selection.len(),
+                            |(idx, _)| idx..idx,
+                        )
+                    } else {
+                        // We parsed a month. Match the first three non-whitespace characters, which must be the month we parsed.
+                        month_chars.next().unwrap().0
+                            ..month_chars
+                                .nth(2)
+                                .map_or(initial_selection.len(), |(idx, _)| idx)
+                    };
+
+                    // Shorten selection to month.
+                    selection.start += month.start;
+                    selection.end = selection.start + month.len();
+                }
+                _ => {}
+            }
+
+            write!(
+                writer,
+                "{}",
+                " ".repeat(UnicodeWidthStr::width(&line[..selection.start]))
+            )?;
+
+            // TODO: Once our minimum supported rust version is at least 1.47, use selection.is_empty() instead.
+            #[allow(clippy::len_zero)]
+            {
+                if selection.len() == 0 {
+                    writeln!(writer, "^ no match for key")?;
+                } else {
+                    writeln!(
+                        writer,
+                        "{}",
+                        "_".repeat(UnicodeWidthStr::width(&line[selection]))
+                    )?;
+                }
+            }
+        }
+        if settings.mode != SortMode::Random
+            && !settings.stable
+            && !settings.unique
+            && (settings.dictionary_order
+                || settings.ignore_leading_blanks
+                || settings.ignore_case
+                || settings.ignore_non_printing
+                || settings.mode != SortMode::Default
+                || settings
+                    .selectors
+                    .last()
+                    .map_or(true, |selector| selector != &Default::default()))
+        {
+            // A last resort comparator is in use, underline the whole line.
+            if self.line.is_empty() {
+                writeln!(writer, "^ no match for key")?;
+            } else {
+                writeln!(
+                    writer,
+                    "{}",
+                    "_".repeat(UnicodeWidthStr::width(line.as_str()))
+                )?;
+            }
+        }
+        Ok(())
+    }
+}
+
+/// Tokenize a line into fields. The result is stored into `token_buffer`.
+fn tokenize(line: &str, separator: Option<char>, token_buffer: &mut Vec<Field>) {
+    assert!(token_buffer.is_empty());
+    if let Some(separator) = separator {
+        tokenize_with_separator(line, separator, token_buffer)
+    } else {
+        tokenize_default(line, token_buffer)
+    }
+}
+
+/// By default fields are separated by the first whitespace after non-whitespace.
+/// Whitespace is included in fields at the start.
+/// The result is stored into `token_buffer`.
+fn tokenize_default(line: &str, token_buffer: &mut Vec<Field>) {
+    token_buffer.push(0..0);
+    // pretend that there was whitespace in front of the line
+    let mut previous_was_whitespace = true;
+    for (idx, char) in line.char_indices() {
+        if char.is_whitespace() {
+            if !previous_was_whitespace {
+                token_buffer.last_mut().unwrap().end = idx;
+                token_buffer.push(idx..0);
+            }
+            previous_was_whitespace = true;
+        } else {
+            previous_was_whitespace = false;
+        }
+    }
+    token_buffer.last_mut().unwrap().end = line.len();
+}
+
+/// Split between separators. These separators are not included in fields.
+/// The result is stored into `token_buffer`.
+fn tokenize_with_separator(line: &str, separator: char, token_buffer: &mut Vec<Field>) {
+    let separator_indices =
+        line.char_indices()
+            .filter_map(|(i, c)| if c == separator { Some(i) } else { None });
+    let mut start = 0;
+    for sep_idx in separator_indices {
+        token_buffer.push(start..sep_idx);
+        start = sep_idx + 1;
+    }
+    if start < line.len() {
+        token_buffer.push(start..line.len());
+    }
+}
+
+#[derive(Clone, PartialEq, Debug)]
+struct KeyPosition {
+    /// 1-indexed, 0 is invalid.
+    field: usize,
+    /// 1-indexed, 0 is end of field.
+    char: usize,
+    ignore_blanks: bool,
+}
+
+impl KeyPosition {
+    fn new(key: &str, default_char_index: usize, ignore_blanks: bool) -> Result<Self, String> {
+        let mut field_and_char = key.split('.');
+
+        let field = field_and_char
+            .next()
+            .ok_or_else(|| format!("invalid key `{}`", key))?;
+        let char = field_and_char.next();
+
+        let field = field
+            .parse()
+            .map_err(|e| format!("failed to parse field index `{}`: {}", field, e))?;
+        if field == 0 {
+            return Err("field index can not be 0".to_string());
+        }
+
+        let char = char.map_or(Ok(default_char_index), |char| {
+            char.parse()
+                .map_err(|e| format!("failed to parse character index `{}`: {}", char, e))
+        })?;
+
+        Ok(Self {
+            field,
+            char,
+            ignore_blanks,
+        })
+    }
+}
+
+impl Default for KeyPosition {
+    fn default() -> Self {
+        KeyPosition {
+            field: 1,
+            char: 1,
+            ignore_blanks: false,
+        }
+    }
+}
+
+#[derive(Clone, PartialEq, Debug)]
+struct FieldSelector {
+    from: KeyPosition,
+    to: Option<KeyPosition>,
+    settings: KeySettings,
+    needs_tokens: bool,
+    // Whether this selector operates on a sub-slice of a line.
+    // Selections are therefore not needed when this selector matches the whole line
+    // or the sort mode is general-numeric.
+    needs_selection: bool,
+}
+
+impl Default for FieldSelector {
+    fn default() -> Self {
+        Self {
+            from: Default::default(),
+            to: None,
+            settings: Default::default(),
+            needs_tokens: false,
+            needs_selection: false,
+        }
+    }
+}
+
+impl FieldSelector {
+    /// Splits this position into the actual position and the attached options.
+    fn split_key_options(position: &str) -> (&str, &str) {
+        if let Some((options_start, _)) = position.char_indices().find(|(_, c)| c.is_alphabetic()) {
+            position.split_at(options_start)
+        } else {
+            (position, "")
+        }
+    }
+
+    fn parse(key: &str, global_settings: &GlobalSettings) -> UResult<Self> {
+        let mut from_to = key.split(',');
+        let (from, from_options) = Self::split_key_options(from_to.next().unwrap());
+        let to = from_to.next().map(|to| Self::split_key_options(to));
+        let options_are_empty = from_options.is_empty() && matches!(to, None | Some((_, "")));
+
+        if options_are_empty {
+            // Inherit the global settings if there are no options attached to this key.
+            (|| {
+                // This would be ideal for a try block, I think. In the meantime this closure allows
+                // to use the `?` operator here.
+                Self::new(
+                    KeyPosition::new(from, 1, global_settings.ignore_leading_blanks)?,
+                    to.map(|(to, _)| {
+                        KeyPosition::new(to, 0, global_settings.ignore_leading_blanks)
+                    })
+                    .transpose()?,
+                    KeySettings::from(global_settings),
+                )
+            })()
+        } else {
+            // Do not inherit from `global_settings`, as there are options attached to this key.
+            Self::parse_with_options((from, from_options), to)
+        }
+        .map_err(|msg| {
+            SortError::ParseKeyError {
+                key: key.to_owned(),
+                msg,
+            }
+            .into()
+        })
+    }
+
+    fn parse_with_options(
+        (from, from_options): (&str, &str),
+        to: Option<(&str, &str)>,
+    ) -> Result<Self, String> {
+        /// Applies `options` to `key_settings`, returning if the 'b'-flag (ignore blanks) was present.
+        fn parse_key_settings(
+            options: &str,
+            key_settings: &mut KeySettings,
+        ) -> Result<bool, String> {
+            let mut ignore_blanks = false;
+            for option in options.chars() {
+                match option {
+                    'M' => key_settings.set_sort_mode(SortMode::Month)?,
+                    'b' => ignore_blanks = true,
+                    'd' => key_settings.set_dictionary_order()?,
+                    'f' => key_settings.ignore_case = true,
+                    'g' => key_settings.set_sort_mode(SortMode::GeneralNumeric)?,
+                    'h' => key_settings.set_sort_mode(SortMode::HumanNumeric)?,
+                    'i' => key_settings.set_ignore_non_printing()?,
+                    'n' => key_settings.set_sort_mode(SortMode::Numeric)?,
+                    'R' => key_settings.set_sort_mode(SortMode::Random)?,
+                    'r' => key_settings.reverse = true,
+                    'V' => key_settings.set_sort_mode(SortMode::Version)?,
+                    c => return Err(format!("invalid option: `{}`", c)),
+                }
+            }
+            Ok(ignore_blanks)
+        }
+
+        let mut key_settings = KeySettings::default();
+        let from = parse_key_settings(from_options, &mut key_settings)
+            .map(|ignore_blanks| KeyPosition::new(from, 1, ignore_blanks))??;
+        let to = if let Some((to, to_options)) = to {
+            Some(
+                parse_key_settings(to_options, &mut key_settings)
+                    .map(|ignore_blanks| KeyPosition::new(to, 0, ignore_blanks))??,
+            )
+        } else {
+            None
+        };
+        Self::new(from, to, key_settings)
+    }
+
+    fn new(
+        from: KeyPosition,
+        to: Option<KeyPosition>,
+        settings: KeySettings,
+    ) -> Result<Self, String> {
+        if from.char == 0 {
+            Err("invalid character index 0 for the start position of a field".to_string())
+        } else {
+            Ok(Self {
+                needs_selection: (from.field != 1
+                    || from.char != 1
+                    || to.is_some()
+                    || matches!(settings.mode, SortMode::Numeric | SortMode::HumanNumeric)
+                    || from.ignore_blanks)
+                    && !matches!(settings.mode, SortMode::GeneralNumeric),
+                needs_tokens: from.field != 1 || from.char == 0 || to.is_some(),
+                from,
+                to,
+                settings,
+            })
+        }
+    }
+
+    /// Get the selection that corresponds to this selector for the line.
+    /// If needs_fields returned false, tokens may be empty.
+    fn get_selection<'a>(&self, line: &'a str, tokens: &[Field]) -> Selection<'a> {
+        // `get_range` expects `None` when we don't need tokens and would get confused by an empty vector.
+        let tokens = if self.needs_tokens {
+            Some(tokens)
+        } else {
+            None
+        };
+        let mut range = &line[self.get_range(line, tokens)];
+        if self.settings.mode == SortMode::Numeric || self.settings.mode == SortMode::HumanNumeric {
+            // Parse NumInfo for this number.
+            let (info, num_range) = NumInfo::parse(
+                range,
+                NumInfoParseSettings {
+                    accept_si_units: self.settings.mode == SortMode::HumanNumeric,
+                    ..Default::default()
+                },
+            );
+            // Shorten the range to what we need to pass to numeric_str_cmp later.
+            range = &range[num_range];
+            Selection::WithNumInfo(range, info)
+        } else if self.settings.mode == SortMode::GeneralNumeric {
+            // Parse this number as f64, as this is the requirement for general numeric sorting.
+            Selection::AsF64(general_f64_parse(&range[get_leading_gen(range)]))
+        } else {
+            // This is not a numeric sort, so we don't need a NumCache.
+            Selection::Str(range)
+        }
+    }
+
+    /// Look up the range in the line that corresponds to this selector.
+    /// If needs_fields returned false, tokens must be None.
+    fn get_range<'a>(&self, line: &'a str, tokens: Option<&[Field]>) -> Range<usize> {
+        enum Resolution {
+            // The start index of the resolved character, inclusive
+            StartOfChar(usize),
+            // The end index of the resolved character, exclusive.
+            // This is only returned if the character index is 0.
+            EndOfChar(usize),
+            // The resolved character would be in front of the first character
+            TooLow,
+            // The resolved character would be after the last character
+            TooHigh,
+        }
+
+        // Get the index for this line given the KeyPosition
+        fn resolve_index(
+            line: &str,
+            tokens: Option<&[Field]>,
+            position: &KeyPosition,
+        ) -> Resolution {
+            if matches!(tokens, Some(tokens) if tokens.len() < position.field) {
+                Resolution::TooHigh
+            } else if position.char == 0 {
+                let end = tokens.unwrap()[position.field - 1].end;
+                if end == 0 {
+                    Resolution::TooLow
+                } else {
+                    Resolution::EndOfChar(end)
+                }
+            } else {
+                let mut idx = if position.field == 1 {
+                    // The first field always starts at 0.
+                    // We don't need tokens for this case.
+                    0
+                } else {
+                    tokens.unwrap()[position.field - 1].start
+                };
+                // strip blanks if needed
+                if position.ignore_blanks {
+                    idx += line[idx..]
+                        .char_indices()
+                        .find(|(_, c)| !c.is_whitespace())
+                        .map_or(line[idx..].len(), |(idx, _)| idx);
+                }
+                // apply the character index
+                idx += line[idx..]
+                    .char_indices()
+                    .nth(position.char - 1)
+                    .map_or(line[idx..].len(), |(idx, _)| idx);
+                if idx >= line.len() {
+                    Resolution::TooHigh
+                } else {
+                    Resolution::StartOfChar(idx)
+                }
+            }
+        }
+
+        match resolve_index(line, tokens, &self.from) {
+            Resolution::StartOfChar(from) => {
+                let to = self.to.as_ref().map(|to| resolve_index(line, tokens, to));
+
+                let mut range = match to {
+                    Some(Resolution::StartOfChar(mut to)) => {
+                        // We need to include the character at `to`.
+                        to += line[to..].chars().next().map_or(1, |c| c.len_utf8());
+                        from..to
+                    }
+                    Some(Resolution::EndOfChar(to)) => from..to,
+                    // If `to` was not given or the match would be after the end of the line,
+                    // match everything until the end of the line.
+                    None | Some(Resolution::TooHigh) => from..line.len(),
+                    // If `to` is before the start of the line, report no match.
+                    // This can happen if the line starts with a separator.
+                    Some(Resolution::TooLow) => 0..0,
+                };
+                if range.start > range.end {
+                    range.end = range.start;
+                }
+                range
+            }
+            Resolution::TooLow | Resolution::EndOfChar(_) => {
+                unreachable!("This should only happen if the field start index is 0, but that should already have caused an error.")
+            }
+            // While for comparisons it's only important that this is an empty slice,
+            // to produce accurate debug output we need to match an empty slice at the end of the line.
+            Resolution::TooHigh => line.len()..line.len(),
+        }
+    }
+}
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [FILE]...
+Write the sorted concatenation of all FILE(s) to standard output.
+Mandatory arguments for long options are mandatory for short options too.
+With no FILE, or when FILE is -, read standard input.",
+        uucore::execution_phrase()
+    )
+}
+
+/// Creates an `Arg` that conflicts with all other sort modes.
+fn make_sort_mode_arg<'a, 'b>(mode: &'a str, short: &'b str, help: &'b str) -> Arg<'a, 'b> {
+    let mut arg = Arg::with_name(mode).short(short).long(mode).help(help);
+    for possible_mode in &options::modes::ALL_SORT_MODES {
+        if *possible_mode != mode {
+            arg = arg.conflicts_with(possible_mode);
+        }
+    }
+    arg
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+    let usage = usage();
+    let mut settings: GlobalSettings = Default::default();
+
+    let matches = match uu_app().usage(&usage[..]).get_matches_from_safe(args) {
+        Ok(t) => t,
+        Err(e) => {
+            // not all clap "Errors" are because of a failure to parse arguments.
+            // "--version" also causes an Error to be returned, but we should not print to stderr
+            // nor return with a non-zero exit code in this case (we should print to stdout and return 0).
+            // This logic is similar to the code in clap, but we return 2 as the exit code in case of real failure
+            // (clap returns 1).
+            if e.use_stderr() {
+                eprintln!("{}", e.message);
+                set_exit_code(2);
+            } else {
+                println!("{}", e.message);
+            }
+            return Ok(());
+        }
+    };
+
+    settings.debug = matches.is_present(options::DEBUG);
+
+    // check whether user specified a zero terminated list of files for input, otherwise read files from args
+    let mut files: Vec<OsString> = if matches.is_present(options::FILES0_FROM) {
+        let files0_from: Vec<OsString> = matches
+            .values_of_os(options::FILES0_FROM)
+            .map(|v| v.map(ToOwned::to_owned).collect())
+            .unwrap_or_default();
+
+        let mut files = Vec::new();
+        for path in &files0_from {
+            let reader = open(&path)?;
+            let buf_reader = BufReader::new(reader);
+            for line in buf_reader.split(b'\0').flatten() {
+                files.push(OsString::from(
+                    std::str::from_utf8(&line)
+                        .expect("Could not parse string from zero terminated input."),
+                ));
+            }
+        }
+        files
+    } else {
+        matches
+            .values_of_os(options::FILES)
+            .map(|v| v.map(ToOwned::to_owned).collect())
+            .unwrap_or_default()
+    };
+
+    settings.mode = if matches.is_present(options::modes::HUMAN_NUMERIC)
+        || matches.value_of(options::modes::SORT) == Some("human-numeric")
+    {
+        SortMode::HumanNumeric
+    } else if matches.is_present(options::modes::MONTH)
+        || matches.value_of(options::modes::SORT) == Some("month")
+    {
+        SortMode::Month
+    } else if matches.is_present(options::modes::GENERAL_NUMERIC)
+        || matches.value_of(options::modes::SORT) == Some("general-numeric")
+    {
+        SortMode::GeneralNumeric
+    } else if matches.is_present(options::modes::NUMERIC)
+        || matches.value_of(options::modes::SORT) == Some("numeric")
+    {
+        SortMode::Numeric
+    } else if matches.is_present(options::modes::VERSION)
+        || matches.value_of(options::modes::SORT) == Some("version")
+    {
+        SortMode::Version
+    } else if matches.is_present(options::modes::RANDOM)
+        || matches.value_of(options::modes::SORT) == Some("random")
+    {
+        settings.salt = Some(get_rand_string());
+        SortMode::Random
+    } else {
+        SortMode::Default
+    };
+
+    settings.dictionary_order = matches.is_present(options::DICTIONARY_ORDER);
+    settings.ignore_non_printing = matches.is_present(options::IGNORE_NONPRINTING);
+    if matches.is_present(options::PARALLEL) {
+        // "0" is default - threads = num of cores
+        settings.threads = matches
+            .value_of(options::PARALLEL)
+            .map(String::from)
+            .unwrap_or_else(|| "0".to_string());
+        env::set_var("RAYON_NUM_THREADS", &settings.threads);
+    }
+
+    settings.buffer_size =
+        matches
+            .value_of(options::BUF_SIZE)
+            .map_or(Ok(DEFAULT_BUF_SIZE), |s| {
+                GlobalSettings::parse_byte_count(s).map_err(|e| {
+                    USimpleError::new(2, format_error_message(e, s, options::BUF_SIZE))
+                })
+            })?;
+
+    let mut tmp_dir = TmpDirWrapper::new(
+        matches
+            .value_of(options::TMP_DIR)
+            .map(PathBuf::from)
+            .unwrap_or_else(env::temp_dir),
+    );
+
+    settings.compress_prog = matches.value_of(options::COMPRESS_PROG).map(String::from);
+
+    if let Some(n_merge) = matches.value_of(options::BATCH_SIZE) {
+        settings.merge_batch_size = n_merge.parse().map_err(|_| {
+            UUsageError::new(2, format!("invalid --batch-size argument '{}'", n_merge))
+        })?;
+    }
+
+    settings.zero_terminated = matches.is_present(options::ZERO_TERMINATED);
+    settings.merge = matches.is_present(options::MERGE);
+
+    settings.check = matches.is_present(options::check::CHECK);
+    if matches.is_present(options::check::CHECK_SILENT)
+        || matches!(
+            matches.value_of(options::check::CHECK),
+            Some(options::check::SILENT) | Some(options::check::QUIET)
+        )
+    {
+        settings.check_silent = true;
+        settings.check = true;
+    };
+
+    settings.ignore_case = matches.is_present(options::IGNORE_CASE);
+
+    settings.ignore_leading_blanks = matches.is_present(options::IGNORE_LEADING_BLANKS);
+
+    settings.reverse = matches.is_present(options::REVERSE);
+    settings.stable = matches.is_present(options::STABLE);
+    settings.unique = matches.is_present(options::UNIQUE);
+
+    if files.is_empty() {
+        /* if no file, default to stdin */
+        files.push("-".to_string().into());
+    } else if settings.check && files.len() != 1 {
+        return Err(UUsageError::new(
+            2,
+            format!(
+                "extra operand `{}' not allowed with -c",
+                files[1].to_string_lossy()
+            ),
+        ));
+    }
+
+    if let Some(arg) = matches.args.get(options::SEPARATOR) {
+        let separator = arg.vals[0].to_string_lossy();
+        let mut separator = separator.as_ref();
+        if separator == "\\0" {
+            separator = "\0";
+        }
+        if separator.len() != 1 {
+            return Err(UUsageError::new(
+                2,
+                "separator must be exactly one character long",
+            ));
+        }
+        settings.separator = Some(separator.chars().next().unwrap())
+    }
+
+    if let Some(values) = matches.values_of(options::KEY) {
+        for value in values {
+            let selector = FieldSelector::parse(value, &settings)?;
+            if selector.settings.mode == SortMode::Random && settings.salt.is_none() {
+                settings.salt = Some(get_rand_string());
+            }
+            settings.selectors.push(selector);
+        }
+    }
+
+    if !matches.is_present(options::KEY) {
+        // add a default selector matching the whole line
+        let key_settings = KeySettings::from(&settings);
+        settings.selectors.push(
+            FieldSelector::new(
+                KeyPosition {
+                    field: 1,
+                    char: 1,
+                    ignore_blanks: key_settings.ignore_blanks,
+                },
+                None,
+                key_settings,
+            )
+            .unwrap(),
+        );
+    }
+
+    // Verify that we can open all input files.
+    // It is the correct behavior to close all files afterwards,
+    // and to reopen them at a later point. This is different from how the output file is handled,
+    // probably to prevent running out of file descriptors.
+    for file in &files {
+        open(file)?;
+    }
+
+    let output = Output::new(matches.value_of(options::OUTPUT))?;
+
+    settings.init_precomputed();
+
+    exec(&mut files, &settings, output, &mut tmp_dir)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::modes::SORT)
+                .long(options::modes::SORT)
+                .takes_value(true)
+                .possible_values(&[
+                    "general-numeric",
+                    "human-numeric",
+                    "month",
+                    "numeric",
+                    "version",
+                    "random",
+                ])
+                .conflicts_with_all(&options::modes::ALL_SORT_MODES),
+        )
+        .arg(make_sort_mode_arg(
+            options::modes::HUMAN_NUMERIC,
+            "h",
+            "compare according to human readable sizes, eg 1M > 100k",
+        ))
+        .arg(make_sort_mode_arg(
+            options::modes::MONTH,
+            "M",
+            "compare according to month name abbreviation",
+        ))
+        .arg(make_sort_mode_arg(
+            options::modes::NUMERIC,
+            "n",
+            "compare according to string numerical value",
+        ))
+        .arg(make_sort_mode_arg(
+            options::modes::GENERAL_NUMERIC,
+            "g",
+            "compare according to string general numerical value",
+        ))
+        .arg(make_sort_mode_arg(
+            options::modes::VERSION,
+            "V",
+            "Sort by SemVer version number, eg 1.12.2 > 1.1.2",
+        ))
+        .arg(make_sort_mode_arg(
+            options::modes::RANDOM,
+            "R",
+            "shuffle in random order",
+        ))
+        .arg(
+            Arg::with_name(options::DICTIONARY_ORDER)
+                .short("d")
+                .long(options::DICTIONARY_ORDER)
+                .help("consider only blanks and alphanumeric characters")
+                .conflicts_with_all(&[
+                    options::modes::NUMERIC,
+                    options::modes::GENERAL_NUMERIC,
+                    options::modes::HUMAN_NUMERIC,
+                    options::modes::MONTH,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::MERGE)
+                .short("m")
+                .long(options::MERGE)
+                .help("merge already sorted files; do not sort"),
+        )
+        .arg(
+            Arg::with_name(options::check::CHECK)
+                .short("c")
+                .long(options::check::CHECK)
+                .takes_value(true)
+                .require_equals(true)
+                .min_values(0)
+                .possible_values(&[
+                    options::check::SILENT,
+                    options::check::QUIET,
+                    options::check::DIAGNOSE_FIRST,
+                ])
+                .conflicts_with(options::OUTPUT)
+                .help("check for sorted input; do not sort"),
+        )
+        .arg(
+            Arg::with_name(options::check::CHECK_SILENT)
+                .short("C")
+                .long(options::check::CHECK_SILENT)
+                .conflicts_with(options::OUTPUT)
+                .help(
+                    "exit successfully if the given file is already sorted,\
+                and exit with status 1 otherwise.",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_CASE)
+                .short("f")
+                .long(options::IGNORE_CASE)
+                .help("fold lower case to upper case characters"),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_NONPRINTING)
+                .short("i")
+                .long(options::IGNORE_NONPRINTING)
+                .help("ignore nonprinting characters")
+                .conflicts_with_all(&[
+                    options::modes::NUMERIC,
+                    options::modes::GENERAL_NUMERIC,
+                    options::modes::HUMAN_NUMERIC,
+                    options::modes::MONTH,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_LEADING_BLANKS)
+                .short("b")
+                .long(options::IGNORE_LEADING_BLANKS)
+                .help("ignore leading blanks when finding sort keys in each line"),
+        )
+        .arg(
+            Arg::with_name(options::OUTPUT)
+                .short("o")
+                .long(options::OUTPUT)
+                .help("write output to FILENAME instead of stdout")
+                .takes_value(true)
+                .value_name("FILENAME"),
+        )
+        .arg(
+            Arg::with_name(options::REVERSE)
+                .short("r")
+                .long(options::REVERSE)
+                .help("reverse the output"),
+        )
+        .arg(
+            Arg::with_name(options::STABLE)
+                .short("s")
+                .long(options::STABLE)
+                .help("stabilize sort by disabling last-resort comparison"),
+        )
+        .arg(
+            Arg::with_name(options::UNIQUE)
+                .short("u")
+                .long(options::UNIQUE)
+                .help("output only the first of an equal run"),
+        )
+        .arg(
+            Arg::with_name(options::KEY)
+                .short("k")
+                .long(options::KEY)
+                .help("sort by a key")
+                .long_help(LONG_HELP_KEYS)
+                .multiple(true)
+                .number_of_values(1)
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::SEPARATOR)
+                .short("t")
+                .long(options::SEPARATOR)
+                .help("custom separator for -k")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::ZERO_TERMINATED)
+                .short("z")
+                .long(options::ZERO_TERMINATED)
+                .help("line delimiter is NUL, not newline"),
+        )
+        .arg(
+            Arg::with_name(options::PARALLEL)
+                .long(options::PARALLEL)
+                .help("change the number of threads running concurrently to NUM_THREADS")
+                .takes_value(true)
+                .value_name("NUM_THREADS"),
+        )
+        .arg(
+            Arg::with_name(options::BUF_SIZE)
+                .short("S")
+                .long(options::BUF_SIZE)
+                .help("sets the maximum SIZE of each segment in number of sorted items")
+                .takes_value(true)
+                .value_name("SIZE"),
+        )
+        .arg(
+            Arg::with_name(options::TMP_DIR)
+                .short("T")
+                .long(options::TMP_DIR)
+                .help("use DIR for temporaries, not $TMPDIR or /tmp")
+                .takes_value(true)
+                .value_name("DIR"),
+        )
+        .arg(
+            Arg::with_name(options::COMPRESS_PROG)
+                .long(options::COMPRESS_PROG)
+                .help("compress temporary files with PROG, decompress with PROG -d")
+                .long_help("PROG has to take input from stdin and output to stdout")
+                .value_name("PROG"),
+        )
+        .arg(
+            Arg::with_name(options::BATCH_SIZE)
+                .long(options::BATCH_SIZE)
+                .help("Merge at most N_MERGE inputs at once.")
+                .value_name("N_MERGE"),
+        )
+        .arg(
+            Arg::with_name(options::FILES0_FROM)
+                .long(options::FILES0_FROM)
+                .help("read input from the files specified by NUL-terminated NUL_FILES")
+                .takes_value(true)
+                .value_name("NUL_FILES")
+                .multiple(true),
+        )
+        .arg(
+            Arg::with_name(options::DEBUG)
+                .long(options::DEBUG)
+                .help("underline the parts of the line that are actually used for sorting"),
+        )
+        .arg(
+            Arg::with_name(options::FILES)
+                .multiple(true)
+                .takes_value(true),
+        )
+}
+
+fn exec(
+    files: &mut [OsString],
+    settings: &GlobalSettings,
+    output: Output,
+    tmp_dir: &mut TmpDirWrapper,
+) -> UResult<()> {
+    if settings.merge {
+        let file_merger = merge::merge(files, settings, output.as_output_name(), tmp_dir)?;
+        file_merger.write_all(settings, output)
+    } else if settings.check {
+        if files.len() > 1 {
+            Err(UUsageError::new(2, "only one file allowed with -c"))
+        } else {
+            check::check(files.first().unwrap(), settings)
+        }
+    } else {
+        let mut lines = files.iter().map(open);
+        ext_sort(&mut lines, settings, output, tmp_dir)
+    }
+}
+
+fn sort_by<'a>(unsorted: &mut Vec<Line<'a>>, settings: &GlobalSettings, line_data: &LineData<'a>) {
+    if settings.stable || settings.unique {
+        unsorted.par_sort_by(|a, b| compare_by(a, b, settings, line_data, line_data))
+    } else {
+        unsorted.par_sort_unstable_by(|a, b| compare_by(a, b, settings, line_data, line_data))
+    }
+}
+
+fn compare_by<'a>(
+    a: &Line<'a>,
+    b: &Line<'a>,
+    global_settings: &GlobalSettings,
+    a_line_data: &LineData<'a>,
+    b_line_data: &LineData<'a>,
+) -> Ordering {
+    let mut selection_index = 0;
+    let mut num_info_index = 0;
+    let mut parsed_float_index = 0;
+    for selector in &global_settings.selectors {
+        let (a_str, b_str) = if !selector.needs_selection {
+            // We can select the whole line.
+            (a.line, b.line)
+        } else {
+            let selections = (
+                a_line_data.selections
+                    [a.index * global_settings.precomputed.selections_per_line + selection_index],
+                b_line_data.selections
+                    [b.index * global_settings.precomputed.selections_per_line + selection_index],
+            );
+            selection_index += 1;
+            selections
+        };
+
+        let settings = &selector.settings;
+
+        let cmp: Ordering = match settings.mode {
+            SortMode::Random => {
+                // check if the two strings are equal
+                if custom_str_cmp(
+                    a_str,
+                    b_str,
+                    settings.ignore_non_printing,
+                    settings.dictionary_order,
+                    settings.ignore_case,
+                ) == Ordering::Equal
+                {
+                    Ordering::Equal
+                } else {
+                    // Only if they are not equal compare by the hash
+                    random_shuffle(a_str, b_str, &global_settings.salt.unwrap())
+                }
+            }
+            SortMode::Numeric => {
+                let a_num_info = &a_line_data.num_infos
+                    [a.index * global_settings.precomputed.num_infos_per_line + num_info_index];
+                let b_num_info = &b_line_data.num_infos
+                    [b.index * global_settings.precomputed.num_infos_per_line + num_info_index];
+                num_info_index += 1;
+                numeric_str_cmp((a_str, a_num_info), (b_str, b_num_info))
+            }
+            SortMode::HumanNumeric => {
+                let a_num_info = &a_line_data.num_infos
+                    [a.index * global_settings.precomputed.num_infos_per_line + num_info_index];
+                let b_num_info = &b_line_data.num_infos
+                    [b.index * global_settings.precomputed.num_infos_per_line + num_info_index];
+                num_info_index += 1;
+                human_numeric_str_cmp((a_str, a_num_info), (b_str, b_num_info))
+            }
+            SortMode::GeneralNumeric => {
+                let a_float = &a_line_data.parsed_floats
+                    [a.index * global_settings.precomputed.floats_per_line + parsed_float_index];
+                let b_float = &b_line_data.parsed_floats
+                    [b.index * global_settings.precomputed.floats_per_line + parsed_float_index];
+                parsed_float_index += 1;
+                general_numeric_compare(a_float, b_float)
+            }
+            SortMode::Month => month_compare(a_str, b_str),
+            SortMode::Version => version_cmp(a_str, b_str),
+            SortMode::Default => custom_str_cmp(
+                a_str,
+                b_str,
+                settings.ignore_non_printing,
+                settings.dictionary_order,
+                settings.ignore_case,
+            ),
+        };
+        if cmp != Ordering::Equal {
+            return if settings.reverse { cmp.reverse() } else { cmp };
+        }
+    }
+
+    // Call "last resort compare" if all selectors returned Equal
+    let cmp = if global_settings.mode == SortMode::Random
+        || global_settings.stable
+        || global_settings.unique
+    {
+        Ordering::Equal
+    } else {
+        a.line.cmp(b.line)
+    };
+
+    if global_settings.reverse {
+        cmp.reverse()
+    } else {
+        cmp
+    }
+}
+
+// This function cleans up the initial comparison done by leading_num_common for a general numeric compare.
+// In contrast to numeric compare, GNU general numeric/FP sort *should* recognize positive signs and
+// scientific notation, so we strip those lines only after the end of the following numeric string.
+// For example, 5e10KFD would be 5e10 or 5x10^10 and +10000HFKJFK would become 10000.
+fn get_leading_gen(input: &str) -> Range<usize> {
+    let trimmed = input.trim_start();
+    let leading_whitespace_len = input.len() - trimmed.len();
+
+    // check for inf, -inf and nan
+    for allowed_prefix in &["inf", "-inf", "nan"] {
+        if trimmed.is_char_boundary(allowed_prefix.len())
+            && trimmed[..allowed_prefix.len()].eq_ignore_ascii_case(allowed_prefix)
+        {
+            return leading_whitespace_len..(leading_whitespace_len + allowed_prefix.len());
+        }
+    }
+    // Make this iter peekable to see if next char is numeric
+    let mut char_indices = itertools::peek_nth(trimmed.char_indices());
+
+    let first = char_indices.peek();
+
+    if matches!(first, Some((_, NEGATIVE)) | Some((_, POSITIVE))) {
+        char_indices.next();
+    }
+
+    let mut had_e_notation = false;
+    let mut had_decimal_pt = false;
+    while let Some((idx, c)) = char_indices.next() {
+        if c.is_ascii_digit() {
+            continue;
+        }
+        if c == DECIMAL_PT && !had_decimal_pt && !had_e_notation {
+            had_decimal_pt = true;
+            continue;
+        }
+        if (c == 'e' || c == 'E') && !had_e_notation {
+            // we can only consume the 'e' if what follow is either a digit, or a sign followed by a digit.
+            if let Some(&(_, next_char)) = char_indices.peek() {
+                if (next_char == '+' || next_char == '-')
+                    && matches!(
+                        char_indices.peek_nth(2),
+                        Some((_, c)) if c.is_ascii_digit()
+                    )
+                {
+                    // Consume the sign. The following digits will be consumed by the main loop.
+                    char_indices.next();
+                    had_e_notation = true;
+                    continue;
+                }
+                if next_char.is_ascii_digit() {
+                    had_e_notation = true;
+                    continue;
+                }
+            }
+        }
+        return leading_whitespace_len..(leading_whitespace_len + idx);
+    }
+    leading_whitespace_len..input.len()
+}
+
+#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
+pub enum GeneralF64ParseResult {
+    Invalid,
+    NaN,
+    NegInfinity,
+    Number(f64),
+    Infinity,
+}
+
+/// Parse the beginning string into a GeneralF64ParseResult.
+/// Using a GeneralF64ParseResult instead of f64 is necessary to correctly order floats.
+#[inline(always)]
+fn general_f64_parse(a: &str) -> GeneralF64ParseResult {
+    // The actual behavior here relies on Rust's implementation of parsing floating points.
+    // For example "nan", "inf" (ignoring the case) and "infinity" are only parsed to floats starting from 1.53.
+    // TODO: Once our minimum supported Rust version is 1.53 or above, we should add tests for those cases.
+    match a.parse::<f64>() {
+        Ok(a) if a.is_nan() => GeneralF64ParseResult::NaN,
+        Ok(a) if a == std::f64::NEG_INFINITY => GeneralF64ParseResult::NegInfinity,
+        Ok(a) if a == std::f64::INFINITY => GeneralF64ParseResult::Infinity,
+        Ok(a) => GeneralF64ParseResult::Number(a),
+        Err(_) => GeneralF64ParseResult::Invalid,
+    }
+}
+
+/// Compares two floats, with errors and non-numerics assumed to be -inf.
+/// Stops coercing at the first non-numeric char.
+/// We explicitly need to convert to f64 in this case.
+fn general_numeric_compare(a: &GeneralF64ParseResult, b: &GeneralF64ParseResult) -> Ordering {
+    a.partial_cmp(b).unwrap()
+}
+
+fn get_rand_string() -> [u8; 16] {
+    thread_rng().sample(rand::distributions::Standard)
+}
+
+fn get_hash<T: Hash>(t: &T) -> u64 {
+    let mut s: FnvHasher = Default::default();
+    t.hash(&mut s);
+    s.finish()
+}
+
+fn random_shuffle(a: &str, b: &str, salt: &[u8]) -> Ordering {
+    let da = get_hash(&(a, salt));
+    let db = get_hash(&(b, salt));
+    da.cmp(&db)
+}
+
+#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy)]
+enum Month {
+    Unknown,
+    January,
+    February,
+    March,
+    April,
+    May,
+    June,
+    July,
+    August,
+    September,
+    October,
+    November,
+    December,
+}
+
+/// Parse the beginning string into a Month, returning Month::Unknown on errors.
+fn month_parse(line: &str) -> Month {
+    let line = line.trim();
+
+    const MONTHS: [(&str, Month); 12] = [
+        ("JAN", Month::January),
+        ("FEB", Month::February),
+        ("MAR", Month::March),
+        ("APR", Month::April),
+        ("MAY", Month::May),
+        ("JUN", Month::June),
+        ("JUL", Month::July),
+        ("AUG", Month::August),
+        ("SEP", Month::September),
+        ("OCT", Month::October),
+        ("NOV", Month::November),
+        ("DEC", Month::December),
+    ];
+
+    for (month_str, month) in &MONTHS {
+        if line.is_char_boundary(month_str.len())
+            && line[..month_str.len()].eq_ignore_ascii_case(month_str)
+        {
+            return *month;
+        }
+    }
+
+    Month::Unknown
+}
+
+fn month_compare(a: &str, b: &str) -> Ordering {
+    #![allow(clippy::comparison_chain)]
+    let ma = month_parse(a);
+    let mb = month_parse(b);
+
+    if ma > mb {
+        Ordering::Greater
+    } else if ma < mb {
+        Ordering::Less
+    } else {
+        Ordering::Equal
+    }
+}
+
+fn print_sorted<'a, T: Iterator<Item = &'a Line<'a>>>(
+    iter: T,
+    settings: &GlobalSettings,
+    output: Output,
+) {
+    let mut writer = output.into_write();
+    for line in iter {
+        line.print(&mut writer, settings);
+    }
+}
+
+/// Strips the trailing " (os error XX)" from io error strings.
+fn strip_errno(err: &str) -> &str {
+    &err[..err.find(" (os error ").unwrap_or(err.len())]
+}
+
+fn open(path: impl AsRef<OsStr>) -> UResult<Box<dyn Read + Send>> {
+    let path = path.as_ref();
+    if path == "-" {
+        let stdin = stdin();
+        return Ok(Box::new(stdin) as Box<dyn Read + Send>);
+    }
+
+    let path = Path::new(path);
+
+    match File::open(path) {
+        Ok(f) => Ok(Box::new(f) as Box<dyn Read + Send>),
+        Err(error) => Err(SortError::ReadFailed {
+            path: path.to_string_lossy().to_string(),
+            error,
+        }
+        .into()),
+    }
+}
+
+fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String {
+    // NOTE:
+    // GNU's sort echos affected flag, -S or --buffer-size, depending user's selection
+    // GNU's sort does distinguish between "invalid (suffix in) argument"
+    match error {
+        ParseSizeError::ParseFailure(_) => format!("invalid --{} argument '{}'", option, s),
+        ParseSizeError::SizeTooBig(_) => format!("--{} argument '{}' too large", option, s),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use super::*;
+
+    fn tokenize_helper(line: &str, separator: Option<char>) -> Vec<Field> {
+        let mut buffer = vec![];
+        tokenize(line, separator, &mut buffer);
+        buffer
+    }
+
+    #[test]
+    fn test_get_hash() {
+        let a = "Ted".to_string();
+
+        assert_eq!(2_646_829_031_758_483_623, get_hash(&a));
+    }
+
+    #[test]
+    fn test_random_shuffle() {
+        let a = "Ted";
+        let b = "Ted";
+        let c = get_rand_string();
+
+        assert_eq!(Ordering::Equal, random_shuffle(a, b, &c));
+    }
+
+    #[test]
+    fn test_month_compare() {
+        let a = "JaN";
+        let b = "OCt";
+
+        assert_eq!(Ordering::Less, month_compare(a, b));
+    }
+    #[test]
+    fn test_version_compare() {
+        let a = "1.2.3-alpha2";
+        let b = "1.4.0";
+
+        assert_eq!(Ordering::Less, version_cmp(a, b));
+    }
+
+    #[test]
+    fn test_random_compare() {
+        let a = "9";
+        let b = "9";
+        let c = get_rand_string();
+
+        assert_eq!(Ordering::Equal, random_shuffle(a, b, &c));
+    }
+
+    #[test]
+    fn test_tokenize_fields() {
+        let line = "foo bar b    x";
+        assert_eq!(tokenize_helper(line, None), vec![0..3, 3..7, 7..9, 9..14,],);
+    }
+
+    #[test]
+    fn test_tokenize_fields_leading_whitespace() {
+        let line = "    foo bar b    x";
+        assert_eq!(
+            tokenize_helper(line, None),
+            vec![0..7, 7..11, 11..13, 13..18,]
+        );
+    }
+
+    #[test]
+    fn test_tokenize_fields_custom_separator() {
+        let line = "aaa foo bar b    x";
+        assert_eq!(
+            tokenize_helper(line, Some('a')),
+            vec![0..0, 1..1, 2..2, 3..9, 10..18,]
+        );
+    }
+
+    #[test]
+    fn test_tokenize_fields_trailing_custom_separator() {
+        let line = "a";
+        assert_eq!(tokenize_helper(line, Some('a')), vec![0..0]);
+        let line = "aa";
+        assert_eq!(tokenize_helper(line, Some('a')), vec![0..0, 1..1]);
+        let line = "..a..a";
+        assert_eq!(tokenize_helper(line, Some('a')), vec![0..2, 3..5]);
+    }
+
+    #[test]
+    #[cfg(target_pointer_width = "64")]
+    fn test_line_size() {
+        // We should make sure to not regress the size of the Line struct because
+        // it is unconditional overhead for every line we sort.
+        assert_eq!(std::mem::size_of::<Line>(), 24);
+    }
+
+    #[test]
+    fn test_parse_byte_count() {
+        let valid_input = [
+            ("0", 0),
+            ("50K", 50 * 1024),
+            ("50k", 50 * 1024),
+            ("1M", 1024 * 1024),
+            ("100M", 100 * 1024 * 1024),
+            #[cfg(not(target_pointer_width = "32"))]
+            ("1000G", 1000 * 1024 * 1024 * 1024),
+            #[cfg(not(target_pointer_width = "32"))]
+            ("10T", 10 * 1024 * 1024 * 1024 * 1024),
+            ("1b", 1),
+            ("1024b", 1024),
+            ("1024Mb", 1024 * 1024 * 1024), // NOTE: This might not be how GNU `sort` behaves for 'Mb'
+            ("1", 1024),                    // K is default
+            ("50", 50 * 1024),
+            ("K", 1024),
+            ("k", 1024),
+            ("m", 1024 * 1024),
+            #[cfg(not(target_pointer_width = "32"))]
+            ("E", 1024 * 1024 * 1024 * 1024 * 1024 * 1024),
+        ];
+        for (input, expected_output) in &valid_input {
+            assert_eq!(
+                GlobalSettings::parse_byte_count(input),
+                Ok(*expected_output)
+            );
+        }
+
+        // SizeTooBig
+        let invalid_input = ["500E", "1Y"];
+        for input in &invalid_input {
+            #[cfg(not(target_pointer_width = "128"))]
+            assert!(GlobalSettings::parse_byte_count(input).is_err());
+        }
+
+        // ParseFailure
+        let invalid_input = ["nonsense", "1B", "B", "b", "p", "e", "z", "y"];
+        for input in &invalid_input {
+            assert!(GlobalSettings::parse_byte_count(input).is_err());
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_sort/tmp_dir.rs.html b/src/uu_sort/tmp_dir.rs.html new file mode 100644 index 000000000..526af7077 --- /dev/null +++ b/src/uu_sort/tmp_dir.rs.html @@ -0,0 +1,175 @@ +tmp_dir.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+
+use std::{
+    fs::File,
+    path::{Path, PathBuf},
+    sync::{Arc, Mutex},
+};
+
+use tempfile::TempDir;
+use uucore::error::{UResult, USimpleError};
+
+use crate::SortError;
+
+/// A wrapper around TempDir that may only exist once in a process.
+///
+/// `TmpDirWrapper` handles the allocation of new temporary files in this temporary directory and
+/// deleting the whole directory when `SIGINT` is received. Creating a second `TmpDirWrapper` will
+/// fail because `ctrlc::set_handler()` fails when there's already a handler.
+/// The directory is only created once the first file is requested.
+pub struct TmpDirWrapper {
+    temp_dir: Option<TempDir>,
+    parent_path: PathBuf,
+    size: usize,
+    lock: Arc<Mutex<()>>,
+}
+
+impl TmpDirWrapper {
+    pub fn new(path: PathBuf) -> Self {
+        Self {
+            parent_path: path,
+            size: 0,
+            temp_dir: None,
+            lock: Default::default(),
+        }
+    }
+
+    fn init_tmp_dir(&mut self) -> UResult<()> {
+        assert!(self.temp_dir.is_none());
+        assert_eq!(self.size, 0);
+        self.temp_dir = Some(
+            tempfile::Builder::new()
+                .prefix("uutils_sort")
+                .tempdir_in(&self.parent_path)
+                .map_err(|_| SortError::TmpDirCreationFailed)?,
+        );
+
+        let path = self.temp_dir.as_ref().unwrap().path().to_owned();
+        let lock = self.lock.clone();
+        ctrlc::set_handler(move || {
+            // Take the lock so that `next_file_path` returns no new file path.
+            let _lock = lock.lock().unwrap();
+            if let Err(e) = remove_tmp_dir(&path) {
+                show_error!("failed to delete temporary directory: {}", e);
+            }
+            std::process::exit(2)
+        })
+        .map_err(|e| USimpleError::new(2, format!("failed to set up signal handler: {}", e)))
+    }
+
+    pub fn next_file(&mut self) -> UResult<(File, PathBuf)> {
+        if self.temp_dir.is_none() {
+            self.init_tmp_dir()?;
+        }
+
+        let _lock = self.lock.lock().unwrap();
+        let file_name = self.size.to_string();
+        self.size += 1;
+        let path = self.temp_dir.as_ref().unwrap().path().join(file_name);
+        Ok((
+            File::create(&path).map_err(|error| SortError::OpenTmpFileFailed { error })?,
+            path,
+        ))
+    }
+}
+
+/// Remove the directory at `path` by deleting its child files and then itself.
+/// Errors while deleting child files are ignored.
+fn remove_tmp_dir(path: &Path) -> std::io::Result<()> {
+    if let Ok(read_dir) = std::fs::read_dir(&path) {
+        for file in read_dir.flatten() {
+            // if we fail to delete the file here it was probably deleted by another thread
+            // in the meantime, but that's ok.
+            let _ = std::fs::remove_file(file.path());
+        }
+    }
+    std::fs::remove_dir(path)
+}
+
+
\ No newline at end of file diff --git a/src/uu_split/platform/mod.rs.html b/src/uu_split/platform/mod.rs.html new file mode 100644 index 000000000..fa2c702be --- /dev/null +++ b/src/uu_split/platform/mod.rs.html @@ -0,0 +1,27 @@ +mod.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+
+#[cfg(unix)]
+pub use self::unix::instantiate_current_writer;
+
+#[cfg(windows)]
+pub use self::windows::instantiate_current_writer;
+
+#[cfg(unix)]
+mod unix;
+
+#[cfg(windows)]
+mod windows;
+
+
\ No newline at end of file diff --git a/src/uu_split/platform/unix.rs.html b/src/uu_split/platform/unix.rs.html new file mode 100644 index 000000000..67cf78448 --- /dev/null +++ b/src/uu_split/platform/unix.rs.html @@ -0,0 +1,251 @@ +unix.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+
+use std::env;
+use std::io::Write;
+use std::io::{BufWriter, Result};
+use std::process::{Child, Command, Stdio};
+/// A writer that writes to a shell_process' stdin
+///
+/// We use a shell process (not directly calling a sub-process) so we can forward the name of the
+/// corresponding output file (xaa, xab, xac… ). This is the way it was implemented in GNU split.
+struct FilterWriter {
+    /// Running shell process
+    shell_process: Child,
+}
+
+impl Write for FilterWriter {
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        self.shell_process
+            .stdin
+            .as_mut()
+            .expect("failed to get shell stdin")
+            .write(buf)
+    }
+    fn flush(&mut self) -> Result<()> {
+        self.shell_process
+            .stdin
+            .as_mut()
+            .expect("failed to get shell stdin")
+            .flush()
+    }
+}
+
+/// Have an environment variable set at a value during this lifetime
+struct WithEnvVarSet {
+    /// Env var key
+    _previous_var_key: String,
+    /// Previous value set to this key
+    _previous_var_value: std::result::Result<String, env::VarError>,
+}
+impl WithEnvVarSet {
+    /// Save previous value assigned to key, set key=value
+    fn new(key: &str, value: &str) -> WithEnvVarSet {
+        let previous_env_value = env::var(key);
+        env::set_var(key, value);
+        WithEnvVarSet {
+            _previous_var_key: String::from(key),
+            _previous_var_value: previous_env_value,
+        }
+    }
+}
+
+impl Drop for WithEnvVarSet {
+    /// Restore previous value now that this is being dropped by context
+    fn drop(&mut self) {
+        if let Ok(ref prev_value) = self._previous_var_value {
+            env::set_var(&self._previous_var_key, &prev_value);
+        } else {
+            env::remove_var(&self._previous_var_key)
+        }
+    }
+}
+impl FilterWriter {
+    /// Create a new filter running a command with $FILE pointing at the output name
+    ///
+    /// #Arguments
+    ///
+    /// * `command` - The shell command to execute
+    /// * `filepath` - Path of the output file (forwarded to command as $FILE)
+    fn new(command: &str, filepath: &str) -> FilterWriter {
+        // set $FILE, save previous value (if there was one)
+        let _with_env_var_set = WithEnvVarSet::new("FILE", filepath);
+
+        let shell_process =
+            Command::new(env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_owned()))
+                .arg("-c")
+                .arg(command)
+                .stdin(Stdio::piped())
+                .spawn()
+                .expect("Couldn't spawn filter command");
+
+        FilterWriter { shell_process }
+    }
+}
+
+impl Drop for FilterWriter {
+    /// flush stdin, close it and wait on `shell_process` before dropping self
+    fn drop(&mut self) {
+        {
+            // close stdin by dropping it
+            let _stdin = self.shell_process.stdin.as_mut();
+        }
+        let exit_status = self
+            .shell_process
+            .wait()
+            .expect("Couldn't wait for child process");
+        if let Some(return_code) = exit_status.code() {
+            if return_code != 0 {
+                crash!(1, "Shell process returned {}", return_code);
+            }
+        } else {
+            crash!(1, "Shell process terminated by signal")
+        }
+    }
+}
+
+/// Instantiate either a file writer or a "write to shell process's stdin" writer
+pub fn instantiate_current_writer(
+    filter: &Option<String>,
+    filename: &str,
+) -> BufWriter<Box<dyn Write>> {
+    match filter {
+        None => BufWriter::new(Box::new(
+            // write to the next file
+            std::fs::OpenOptions::new()
+                .write(true)
+                .create(true)
+                .open(std::path::Path::new(&filename))
+                .unwrap(),
+        ) as Box<dyn Write>),
+        Some(ref filter_command) => BufWriter::new(Box::new(
+            // spawn a shell command and write to it
+            FilterWriter::new(filter_command, filename),
+        ) as Box<dyn Write>),
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_split/split.rs.html b/src/uu_split/split.rs.html new file mode 100644 index 000000000..c16e50ae2 --- /dev/null +++ b/src/uu_split/split.rs.html @@ -0,0 +1,853 @@ +split.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Akira Hayakawa <ruby.wktk@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) PREFIXaa
+
+#[macro_use]
+extern crate uucore;
+
+mod platform;
+
+use clap::{crate_version, App, Arg};
+use std::convert::TryFrom;
+use std::env;
+use std::fs::File;
+use std::io::{stdin, BufRead, BufReader, BufWriter, Read, Write};
+use std::path::Path;
+use std::{char, fs::remove_file};
+use uucore::parse_size::parse_size;
+
+static OPT_BYTES: &str = "bytes";
+static OPT_LINE_BYTES: &str = "line-bytes";
+static OPT_LINES: &str = "lines";
+static OPT_ADDITIONAL_SUFFIX: &str = "additional-suffix";
+static OPT_FILTER: &str = "filter";
+static OPT_NUMERIC_SUFFIXES: &str = "numeric-suffixes";
+static OPT_SUFFIX_LENGTH: &str = "suffix-length";
+static OPT_DEFAULT_SUFFIX_LENGTH: &str = "2";
+static OPT_VERBOSE: &str = "verbose";
+
+static ARG_INPUT: &str = "input";
+static ARG_PREFIX: &str = "prefix";
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [INPUT [PREFIX]]",
+        uucore::execution_phrase()
+    )
+}
+fn get_long_usage() -> String {
+    format!(
+        "Usage:
+  {0}
+
+Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default
+size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is
+-, read standard input.",
+        usage()
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let long_usage = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&long_usage[..])
+        .get_matches_from(args);
+
+    let mut settings = Settings {
+        prefix: "".to_owned(),
+        numeric_suffix: false,
+        suffix_length: 0,
+        additional_suffix: "".to_owned(),
+        input: "".to_owned(),
+        filter: None,
+        strategy: "".to_owned(),
+        strategy_param: "".to_owned(),
+        verbose: false,
+    };
+
+    settings.suffix_length = matches
+        .value_of(OPT_SUFFIX_LENGTH)
+        .unwrap()
+        .parse()
+        .unwrap_or_else(|_| panic!("Invalid number for {}", OPT_SUFFIX_LENGTH));
+
+    settings.numeric_suffix = matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0;
+    settings.additional_suffix = matches.value_of(OPT_ADDITIONAL_SUFFIX).unwrap().to_owned();
+
+    settings.verbose = matches.occurrences_of("verbose") > 0;
+    // check that the user is not specifying more than one strategy
+    // note: right now, this exact behavior cannot be handled by ArgGroup since ArgGroup
+    // considers a default value Arg as "defined"
+    let explicit_strategies =
+        vec![OPT_LINE_BYTES, OPT_LINES, OPT_BYTES]
+            .into_iter()
+            .fold(0, |count, strategy| {
+                if matches.occurrences_of(strategy) > 0 {
+                    count + 1
+                } else {
+                    count
+                }
+            });
+    if explicit_strategies > 1 {
+        crash!(1, "cannot split in more than one way");
+    }
+
+    // default strategy (if no strategy is passed, use this one)
+    settings.strategy = String::from(OPT_LINES);
+    settings.strategy_param = matches.value_of(OPT_LINES).unwrap().to_owned();
+    // take any (other) defined strategy
+    for &strategy in &[OPT_LINE_BYTES, OPT_BYTES] {
+        if matches.occurrences_of(strategy) > 0 {
+            settings.strategy = String::from(strategy);
+            settings.strategy_param = matches.value_of(strategy).unwrap().to_owned();
+        }
+    }
+
+    settings.input = matches.value_of(ARG_INPUT).unwrap().to_owned();
+    settings.prefix = matches.value_of(ARG_PREFIX).unwrap().to_owned();
+
+    if matches.occurrences_of(OPT_FILTER) > 0 {
+        if cfg!(windows) {
+            // see https://github.com/rust-lang/rust/issues/29494
+            show_error!("{} is currently not supported in this platform", OPT_FILTER);
+            exit!(-1);
+        } else {
+            settings.filter = Some(matches.value_of(OPT_FILTER).unwrap().to_owned());
+        }
+    }
+
+    split(&settings)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about("Create output files containing consecutive or interleaved sections of input")
+        // strategy (mutually exclusive)
+        .arg(
+            Arg::with_name(OPT_BYTES)
+                .short("b")
+                .long(OPT_BYTES)
+                .takes_value(true)
+                .default_value("2")
+                .help("use suffixes of length N (default 2)"),
+        )
+        .arg(
+            Arg::with_name(OPT_LINE_BYTES)
+                .short("C")
+                .long(OPT_LINE_BYTES)
+                .takes_value(true)
+                .default_value("2")
+                .help("put at most SIZE bytes of lines per output file"),
+        )
+        .arg(
+            Arg::with_name(OPT_LINES)
+                .short("l")
+                .long(OPT_LINES)
+                .takes_value(true)
+                .default_value("1000")
+                .help("write to shell COMMAND file name is $FILE (Currently not implemented for Windows)"),
+        )
+        // rest of the arguments
+        .arg(
+            Arg::with_name(OPT_ADDITIONAL_SUFFIX)
+                .long(OPT_ADDITIONAL_SUFFIX)
+                .takes_value(true)
+                .default_value("")
+                .help("additional suffix to append to output file names"),
+        )
+        .arg(
+            Arg::with_name(OPT_FILTER)
+                .long(OPT_FILTER)
+                .takes_value(true)
+                .help("write to shell COMMAND file name is $FILE (Currently not implemented for Windows)"),
+        )
+        .arg(
+            Arg::with_name(OPT_NUMERIC_SUFFIXES)
+                .short("d")
+                .long(OPT_NUMERIC_SUFFIXES)
+                .takes_value(true)
+                .default_value("0")
+                .help("use numeric suffixes instead of alphabetic"),
+        )
+        .arg(
+            Arg::with_name(OPT_SUFFIX_LENGTH)
+                .short("a")
+                .long(OPT_SUFFIX_LENGTH)
+                .takes_value(true)
+                .default_value(OPT_DEFAULT_SUFFIX_LENGTH)
+                .help("use suffixes of length N (default 2)"),
+        )
+        .arg(
+            Arg::with_name(OPT_VERBOSE)
+                .long(OPT_VERBOSE)
+                .help("print a diagnostic just before each output file is opened"),
+        )
+        .arg(
+            Arg::with_name(ARG_INPUT)
+            .takes_value(true)
+            .default_value("-")
+            .index(1)
+        )
+        .arg(
+            Arg::with_name(ARG_PREFIX)
+            .takes_value(true)
+            .default_value("x")
+            .index(2)
+        )
+}
+
+#[allow(dead_code)]
+struct Settings {
+    prefix: String,
+    numeric_suffix: bool,
+    suffix_length: usize,
+    additional_suffix: String,
+    input: String,
+    /// When supplied, a shell command to output to instead of xaa, xab …
+    filter: Option<String>,
+    strategy: String,
+    strategy_param: String,
+    verbose: bool, // TODO: warning: field is never read: `verbose`
+}
+
+trait Splitter {
+    // Consume as much as possible from `reader` so as to saturate `writer`.
+    // Equivalent to finishing one of the part files. Returns the number of
+    // bytes that have been moved.
+    fn consume(
+        &mut self,
+        reader: &mut BufReader<Box<dyn Read>>,
+        writer: &mut BufWriter<Box<dyn Write>>,
+    ) -> u128;
+}
+
+struct LineSplitter {
+    lines_per_split: usize,
+}
+
+impl LineSplitter {
+    fn new(settings: &Settings) -> LineSplitter {
+        LineSplitter {
+            lines_per_split: settings.strategy_param.parse().unwrap_or_else(|_| {
+                crash!(1, "invalid number of lines: '{}'", settings.strategy_param)
+            }),
+        }
+    }
+}
+
+impl Splitter for LineSplitter {
+    fn consume(
+        &mut self,
+        reader: &mut BufReader<Box<dyn Read>>,
+        writer: &mut BufWriter<Box<dyn Write>>,
+    ) -> u128 {
+        let mut bytes_consumed = 0u128;
+        let mut buffer = String::with_capacity(1024);
+        for _ in 0..self.lines_per_split {
+            let bytes_read = reader
+                .read_line(&mut buffer)
+                .unwrap_or_else(|_| crash!(1, "error reading bytes from input file"));
+            // If we ever read 0 bytes then we know we've hit EOF.
+            if bytes_read == 0 {
+                return bytes_consumed;
+            }
+
+            writer
+                .write_all(buffer.as_bytes())
+                .unwrap_or_else(|_| crash!(1, "error writing bytes to output file"));
+            // Empty out the String buffer since `read_line` appends instead of
+            // replaces.
+            buffer.clear();
+
+            bytes_consumed += bytes_read as u128;
+        }
+
+        bytes_consumed
+    }
+}
+
+struct ByteSplitter {
+    bytes_per_split: u128,
+}
+
+impl ByteSplitter {
+    fn new(settings: &Settings) -> ByteSplitter {
+        let size_string = &settings.strategy_param;
+        let size_num = match parse_size(size_string) {
+            Ok(n) => n,
+            Err(e) => crash!(1, "invalid number of bytes: {}", e.to_string()),
+        };
+
+        ByteSplitter {
+            bytes_per_split: u128::try_from(size_num).unwrap(),
+        }
+    }
+}
+
+impl Splitter for ByteSplitter {
+    fn consume(
+        &mut self,
+        reader: &mut BufReader<Box<dyn Read>>,
+        writer: &mut BufWriter<Box<dyn Write>>,
+    ) -> u128 {
+        // We buffer reads and writes. We proceed until `bytes_consumed` is
+        // equal to `self.bytes_per_split` or we reach EOF.
+        let mut bytes_consumed = 0u128;
+        const BUFFER_SIZE: usize = 1024;
+        let mut buffer = [0u8; BUFFER_SIZE];
+        while bytes_consumed < self.bytes_per_split {
+            // Don't overshoot `self.bytes_per_split`! Note: Using std::cmp::min
+            // doesn't really work since we have to get types to match which
+            // can't be done in a way that keeps all conversions safe.
+            let bytes_desired = if (BUFFER_SIZE as u128) <= self.bytes_per_split - bytes_consumed {
+                BUFFER_SIZE
+            } else {
+                // This is a safe conversion since the difference must be less
+                // than BUFFER_SIZE in this branch.
+                (self.bytes_per_split - bytes_consumed) as usize
+            };
+            let bytes_read = reader
+                .read(&mut buffer[0..bytes_desired])
+                .unwrap_or_else(|_| crash!(1, "error reading bytes from input file"));
+            // If we ever read 0 bytes then we know we've hit EOF.
+            if bytes_read == 0 {
+                return bytes_consumed;
+            }
+
+            writer
+                .write_all(&buffer[0..bytes_read])
+                .unwrap_or_else(|_| crash!(1, "error writing bytes to output file"));
+
+            bytes_consumed += bytes_read as u128;
+        }
+
+        bytes_consumed
+    }
+}
+
+// (1, 3) -> "aab"
+#[allow(clippy::many_single_char_names)]
+fn str_prefix(i: usize, width: usize) -> String {
+    let mut c = "".to_owned();
+    let mut n = i;
+    let mut w = width;
+    while w > 0 {
+        w -= 1;
+        let div = 26usize.pow(w as u32);
+        let r = n / div;
+        n -= r * div;
+        c.push(char::from_u32((r as u32) + 97).unwrap());
+    }
+    c
+}
+
+// (1, 3) -> "001"
+#[allow(clippy::many_single_char_names)]
+fn num_prefix(i: usize, width: usize) -> String {
+    let mut c = "".to_owned();
+    let mut n = i;
+    let mut w = width;
+    while w > 0 {
+        w -= 1;
+        let div = 10usize.pow(w as u32);
+        let r = n / div;
+        n -= r * div;
+        c.push(char::from_digit(r as u32, 10).unwrap());
+    }
+    c
+}
+
+fn split(settings: &Settings) -> i32 {
+    let mut reader = BufReader::new(if settings.input == "-" {
+        Box::new(stdin()) as Box<dyn Read>
+    } else {
+        let r = File::open(Path::new(&settings.input)).unwrap_or_else(|_| {
+            crash!(
+                1,
+                "cannot open '{}' for reading: No such file or directory",
+                settings.input
+            )
+        });
+        Box::new(r) as Box<dyn Read>
+    });
+
+    let mut splitter: Box<dyn Splitter> = match settings.strategy.as_str() {
+        s if s == OPT_LINES => Box::new(LineSplitter::new(settings)),
+        s if (s == OPT_BYTES || s == OPT_LINE_BYTES) => Box::new(ByteSplitter::new(settings)),
+        a => crash!(1, "strategy {} not supported", a),
+    };
+
+    let mut fileno = 0;
+    loop {
+        // Get a new part file set up, and construct `writer` for it.
+        let mut filename = settings.prefix.clone();
+        filename.push_str(
+            if settings.numeric_suffix {
+                num_prefix(fileno, settings.suffix_length)
+            } else {
+                str_prefix(fileno, settings.suffix_length)
+            }
+            .as_ref(),
+        );
+        filename.push_str(settings.additional_suffix.as_ref());
+        let mut writer = platform::instantiate_current_writer(&settings.filter, filename.as_str());
+
+        let bytes_consumed = splitter.consume(&mut reader, &mut writer);
+        writer
+            .flush()
+            .unwrap_or_else(|e| crash!(1, "error flushing to output file: {}", e));
+
+        // If we didn't write anything we should clean up the empty file, and
+        // break from the loop.
+        if bytes_consumed == 0 {
+            // The output file is only ever created if --filter isn't used.
+            // Complicated, I know...
+            if settings.filter.is_none() {
+                remove_file(filename)
+                    .unwrap_or_else(|e| crash!(1, "error removing empty file: {}", e));
+            }
+            break;
+        }
+
+        fileno += 1;
+    }
+    0
+}
+
+
\ No newline at end of file diff --git a/src/uu_stat/stat.rs.html b/src/uu_stat/stat.rs.html new file mode 100644 index 000000000..d8cbaaa29 --- /dev/null +++ b/src/uu_stat/stat.rs.html @@ -0,0 +1,2031 @@ +stat.rs - source + +
   1
+   2
+   3
+   4
+   5
+   6
+   7
+   8
+   9
+  10
+  11
+  12
+  13
+  14
+  15
+  16
+  17
+  18
+  19
+  20
+  21
+  22
+  23
+  24
+  25
+  26
+  27
+  28
+  29
+  30
+  31
+  32
+  33
+  34
+  35
+  36
+  37
+  38
+  39
+  40
+  41
+  42
+  43
+  44
+  45
+  46
+  47
+  48
+  49
+  50
+  51
+  52
+  53
+  54
+  55
+  56
+  57
+  58
+  59
+  60
+  61
+  62
+  63
+  64
+  65
+  66
+  67
+  68
+  69
+  70
+  71
+  72
+  73
+  74
+  75
+  76
+  77
+  78
+  79
+  80
+  81
+  82
+  83
+  84
+  85
+  86
+  87
+  88
+  89
+  90
+  91
+  92
+  93
+  94
+  95
+  96
+  97
+  98
+  99
+ 100
+ 101
+ 102
+ 103
+ 104
+ 105
+ 106
+ 107
+ 108
+ 109
+ 110
+ 111
+ 112
+ 113
+ 114
+ 115
+ 116
+ 117
+ 118
+ 119
+ 120
+ 121
+ 122
+ 123
+ 124
+ 125
+ 126
+ 127
+ 128
+ 129
+ 130
+ 131
+ 132
+ 133
+ 134
+ 135
+ 136
+ 137
+ 138
+ 139
+ 140
+ 141
+ 142
+ 143
+ 144
+ 145
+ 146
+ 147
+ 148
+ 149
+ 150
+ 151
+ 152
+ 153
+ 154
+ 155
+ 156
+ 157
+ 158
+ 159
+ 160
+ 161
+ 162
+ 163
+ 164
+ 165
+ 166
+ 167
+ 168
+ 169
+ 170
+ 171
+ 172
+ 173
+ 174
+ 175
+ 176
+ 177
+ 178
+ 179
+ 180
+ 181
+ 182
+ 183
+ 184
+ 185
+ 186
+ 187
+ 188
+ 189
+ 190
+ 191
+ 192
+ 193
+ 194
+ 195
+ 196
+ 197
+ 198
+ 199
+ 200
+ 201
+ 202
+ 203
+ 204
+ 205
+ 206
+ 207
+ 208
+ 209
+ 210
+ 211
+ 212
+ 213
+ 214
+ 215
+ 216
+ 217
+ 218
+ 219
+ 220
+ 221
+ 222
+ 223
+ 224
+ 225
+ 226
+ 227
+ 228
+ 229
+ 230
+ 231
+ 232
+ 233
+ 234
+ 235
+ 236
+ 237
+ 238
+ 239
+ 240
+ 241
+ 242
+ 243
+ 244
+ 245
+ 246
+ 247
+ 248
+ 249
+ 250
+ 251
+ 252
+ 253
+ 254
+ 255
+ 256
+ 257
+ 258
+ 259
+ 260
+ 261
+ 262
+ 263
+ 264
+ 265
+ 266
+ 267
+ 268
+ 269
+ 270
+ 271
+ 272
+ 273
+ 274
+ 275
+ 276
+ 277
+ 278
+ 279
+ 280
+ 281
+ 282
+ 283
+ 284
+ 285
+ 286
+ 287
+ 288
+ 289
+ 290
+ 291
+ 292
+ 293
+ 294
+ 295
+ 296
+ 297
+ 298
+ 299
+ 300
+ 301
+ 302
+ 303
+ 304
+ 305
+ 306
+ 307
+ 308
+ 309
+ 310
+ 311
+ 312
+ 313
+ 314
+ 315
+ 316
+ 317
+ 318
+ 319
+ 320
+ 321
+ 322
+ 323
+ 324
+ 325
+ 326
+ 327
+ 328
+ 329
+ 330
+ 331
+ 332
+ 333
+ 334
+ 335
+ 336
+ 337
+ 338
+ 339
+ 340
+ 341
+ 342
+ 343
+ 344
+ 345
+ 346
+ 347
+ 348
+ 349
+ 350
+ 351
+ 352
+ 353
+ 354
+ 355
+ 356
+ 357
+ 358
+ 359
+ 360
+ 361
+ 362
+ 363
+ 364
+ 365
+ 366
+ 367
+ 368
+ 369
+ 370
+ 371
+ 372
+ 373
+ 374
+ 375
+ 376
+ 377
+ 378
+ 379
+ 380
+ 381
+ 382
+ 383
+ 384
+ 385
+ 386
+ 387
+ 388
+ 389
+ 390
+ 391
+ 392
+ 393
+ 394
+ 395
+ 396
+ 397
+ 398
+ 399
+ 400
+ 401
+ 402
+ 403
+ 404
+ 405
+ 406
+ 407
+ 408
+ 409
+ 410
+ 411
+ 412
+ 413
+ 414
+ 415
+ 416
+ 417
+ 418
+ 419
+ 420
+ 421
+ 422
+ 423
+ 424
+ 425
+ 426
+ 427
+ 428
+ 429
+ 430
+ 431
+ 432
+ 433
+ 434
+ 435
+ 436
+ 437
+ 438
+ 439
+ 440
+ 441
+ 442
+ 443
+ 444
+ 445
+ 446
+ 447
+ 448
+ 449
+ 450
+ 451
+ 452
+ 453
+ 454
+ 455
+ 456
+ 457
+ 458
+ 459
+ 460
+ 461
+ 462
+ 463
+ 464
+ 465
+ 466
+ 467
+ 468
+ 469
+ 470
+ 471
+ 472
+ 473
+ 474
+ 475
+ 476
+ 477
+ 478
+ 479
+ 480
+ 481
+ 482
+ 483
+ 484
+ 485
+ 486
+ 487
+ 488
+ 489
+ 490
+ 491
+ 492
+ 493
+ 494
+ 495
+ 496
+ 497
+ 498
+ 499
+ 500
+ 501
+ 502
+ 503
+ 504
+ 505
+ 506
+ 507
+ 508
+ 509
+ 510
+ 511
+ 512
+ 513
+ 514
+ 515
+ 516
+ 517
+ 518
+ 519
+ 520
+ 521
+ 522
+ 523
+ 524
+ 525
+ 526
+ 527
+ 528
+ 529
+ 530
+ 531
+ 532
+ 533
+ 534
+ 535
+ 536
+ 537
+ 538
+ 539
+ 540
+ 541
+ 542
+ 543
+ 544
+ 545
+ 546
+ 547
+ 548
+ 549
+ 550
+ 551
+ 552
+ 553
+ 554
+ 555
+ 556
+ 557
+ 558
+ 559
+ 560
+ 561
+ 562
+ 563
+ 564
+ 565
+ 566
+ 567
+ 568
+ 569
+ 570
+ 571
+ 572
+ 573
+ 574
+ 575
+ 576
+ 577
+ 578
+ 579
+ 580
+ 581
+ 582
+ 583
+ 584
+ 585
+ 586
+ 587
+ 588
+ 589
+ 590
+ 591
+ 592
+ 593
+ 594
+ 595
+ 596
+ 597
+ 598
+ 599
+ 600
+ 601
+ 602
+ 603
+ 604
+ 605
+ 606
+ 607
+ 608
+ 609
+ 610
+ 611
+ 612
+ 613
+ 614
+ 615
+ 616
+ 617
+ 618
+ 619
+ 620
+ 621
+ 622
+ 623
+ 624
+ 625
+ 626
+ 627
+ 628
+ 629
+ 630
+ 631
+ 632
+ 633
+ 634
+ 635
+ 636
+ 637
+ 638
+ 639
+ 640
+ 641
+ 642
+ 643
+ 644
+ 645
+ 646
+ 647
+ 648
+ 649
+ 650
+ 651
+ 652
+ 653
+ 654
+ 655
+ 656
+ 657
+ 658
+ 659
+ 660
+ 661
+ 662
+ 663
+ 664
+ 665
+ 666
+ 667
+ 668
+ 669
+ 670
+ 671
+ 672
+ 673
+ 674
+ 675
+ 676
+ 677
+ 678
+ 679
+ 680
+ 681
+ 682
+ 683
+ 684
+ 685
+ 686
+ 687
+ 688
+ 689
+ 690
+ 691
+ 692
+ 693
+ 694
+ 695
+ 696
+ 697
+ 698
+ 699
+ 700
+ 701
+ 702
+ 703
+ 704
+ 705
+ 706
+ 707
+ 708
+ 709
+ 710
+ 711
+ 712
+ 713
+ 714
+ 715
+ 716
+ 717
+ 718
+ 719
+ 720
+ 721
+ 722
+ 723
+ 724
+ 725
+ 726
+ 727
+ 728
+ 729
+ 730
+ 731
+ 732
+ 733
+ 734
+ 735
+ 736
+ 737
+ 738
+ 739
+ 740
+ 741
+ 742
+ 743
+ 744
+ 745
+ 746
+ 747
+ 748
+ 749
+ 750
+ 751
+ 752
+ 753
+ 754
+ 755
+ 756
+ 757
+ 758
+ 759
+ 760
+ 761
+ 762
+ 763
+ 764
+ 765
+ 766
+ 767
+ 768
+ 769
+ 770
+ 771
+ 772
+ 773
+ 774
+ 775
+ 776
+ 777
+ 778
+ 779
+ 780
+ 781
+ 782
+ 783
+ 784
+ 785
+ 786
+ 787
+ 788
+ 789
+ 790
+ 791
+ 792
+ 793
+ 794
+ 795
+ 796
+ 797
+ 798
+ 799
+ 800
+ 801
+ 802
+ 803
+ 804
+ 805
+ 806
+ 807
+ 808
+ 809
+ 810
+ 811
+ 812
+ 813
+ 814
+ 815
+ 816
+ 817
+ 818
+ 819
+ 820
+ 821
+ 822
+ 823
+ 824
+ 825
+ 826
+ 827
+ 828
+ 829
+ 830
+ 831
+ 832
+ 833
+ 834
+ 835
+ 836
+ 837
+ 838
+ 839
+ 840
+ 841
+ 842
+ 843
+ 844
+ 845
+ 846
+ 847
+ 848
+ 849
+ 850
+ 851
+ 852
+ 853
+ 854
+ 855
+ 856
+ 857
+ 858
+ 859
+ 860
+ 861
+ 862
+ 863
+ 864
+ 865
+ 866
+ 867
+ 868
+ 869
+ 870
+ 871
+ 872
+ 873
+ 874
+ 875
+ 876
+ 877
+ 878
+ 879
+ 880
+ 881
+ 882
+ 883
+ 884
+ 885
+ 886
+ 887
+ 888
+ 889
+ 890
+ 891
+ 892
+ 893
+ 894
+ 895
+ 896
+ 897
+ 898
+ 899
+ 900
+ 901
+ 902
+ 903
+ 904
+ 905
+ 906
+ 907
+ 908
+ 909
+ 910
+ 911
+ 912
+ 913
+ 914
+ 915
+ 916
+ 917
+ 918
+ 919
+ 920
+ 921
+ 922
+ 923
+ 924
+ 925
+ 926
+ 927
+ 928
+ 929
+ 930
+ 931
+ 932
+ 933
+ 934
+ 935
+ 936
+ 937
+ 938
+ 939
+ 940
+ 941
+ 942
+ 943
+ 944
+ 945
+ 946
+ 947
+ 948
+ 949
+ 950
+ 951
+ 952
+ 953
+ 954
+ 955
+ 956
+ 957
+ 958
+ 959
+ 960
+ 961
+ 962
+ 963
+ 964
+ 965
+ 966
+ 967
+ 968
+ 969
+ 970
+ 971
+ 972
+ 973
+ 974
+ 975
+ 976
+ 977
+ 978
+ 979
+ 980
+ 981
+ 982
+ 983
+ 984
+ 985
+ 986
+ 987
+ 988
+ 989
+ 990
+ 991
+ 992
+ 993
+ 994
+ 995
+ 996
+ 997
+ 998
+ 999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+use uucore::entries;
+use uucore::fs::display_permissions;
+use uucore::fsext::{
+    pretty_filetype, pretty_fstype, pretty_time, read_fs_list, statfs, BirthTime, FsMeta,
+};
+use uucore::libc::mode_t;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use std::borrow::Cow;
+use std::convert::AsRef;
+use std::os::unix::fs::{FileTypeExt, MetadataExt};
+use std::path::Path;
+use std::{cmp, fs, iter};
+
+macro_rules! check_bound {
+    ($str: ident, $bound:expr, $beg: expr, $end: expr) => {
+        if $end >= $bound {
+            return Err(format!("'{}': invalid directive", &$str[$beg..$end]));
+        }
+    };
+}
+macro_rules! fill_string {
+    ($str: ident, $c: expr, $cnt: expr) => {
+        iter::repeat($c)
+            .take($cnt)
+            .map(|c| $str.push(c))
+            .all(|_| true)
+    };
+}
+macro_rules! extend_digits {
+    ($str: expr, $min: expr) => {
+        if $min > $str.len() {
+            let mut pad = String::with_capacity($min);
+            fill_string!(pad, '0', $min - $str.len());
+            pad.push_str($str);
+            pad.into()
+        } else {
+            $str.into()
+        }
+    };
+}
+macro_rules! pad_and_print {
+    ($result: ident, $str: ident, $left: expr, $width: expr, $padding: expr) => {
+        if $str.len() < $width {
+            if $left {
+                $result.push_str($str.as_ref());
+                fill_string!($result, $padding, $width - $str.len());
+            } else {
+                fill_string!($result, $padding, $width - $str.len());
+                $result.push_str($str.as_ref());
+            }
+        } else {
+            $result.push_str($str.as_ref());
+        }
+        print!("{}", $result);
+    };
+}
+macro_rules! print_adjusted {
+    ($str: ident, $left: expr, $width: expr, $padding: expr) => {
+        let field_width = cmp::max($width, $str.len());
+        let mut result = String::with_capacity(field_width);
+        pad_and_print!(result, $str, $left, field_width, $padding);
+    };
+    ($str: ident, $left: expr, $need_prefix: expr, $prefix: expr, $width: expr, $padding: expr) => {
+        let mut field_width = cmp::max($width, $str.len());
+        let mut result = String::with_capacity(field_width + $prefix.len());
+        if $need_prefix {
+            result.push_str($prefix);
+            field_width -= $prefix.len();
+        }
+        pad_and_print!(result, $str, $left, field_width, $padding);
+    };
+}
+
+static ABOUT: &str = "Display file or file system status.";
+
+pub mod options {
+    pub static DEREFERENCE: &str = "dereference";
+    pub static FILE_SYSTEM: &str = "file-system";
+    pub static FORMAT: &str = "format";
+    pub static PRINTF: &str = "printf";
+    pub static TERSE: &str = "terse";
+}
+
+static ARG_FILES: &str = "files";
+
+pub const F_ALTER: u8 = 1;
+pub const F_ZERO: u8 = 1 << 1;
+pub const F_LEFT: u8 = 1 << 2;
+pub const F_SPACE: u8 = 1 << 3;
+pub const F_SIGN: u8 = 1 << 4;
+// unused at present
+pub const F_GROUP: u8 = 1 << 5;
+
+#[derive(Debug, PartialEq)]
+pub enum OutputType {
+    Str,
+    Integer,
+    Unsigned,
+    UnsignedHex,
+    UnsignedOct,
+    Unknown,
+}
+
+#[derive(Debug, PartialEq)]
+pub enum Token {
+    Char(char),
+    Directive {
+        flag: u8,
+        width: usize,
+        precision: i32,
+        format: char,
+    },
+}
+
+pub trait ScanUtil {
+    fn scan_num<F>(&self) -> Option<(F, usize)>
+    where
+        F: std::str::FromStr;
+    fn scan_char(&self, radix: u32) -> Option<(char, usize)>;
+}
+
+impl ScanUtil for str {
+    fn scan_num<F>(&self) -> Option<(F, usize)>
+    where
+        F: std::str::FromStr,
+    {
+        let mut chars = self.chars();
+        let mut i = 0;
+        match chars.next() {
+            Some('-') | Some('+') | Some('0'..='9') => i += 1,
+            _ => return None,
+        }
+        for c in chars {
+            match c {
+                '0'..='9' => i += 1,
+                _ => break,
+            }
+        }
+        if i > 0 {
+            F::from_str(&self[..i]).ok().map(|x| (x, i))
+        } else {
+            None
+        }
+    }
+
+    fn scan_char(&self, radix: u32) -> Option<(char, usize)> {
+        let count = match radix {
+            8 => 3_usize,
+            16 => 2,
+            _ => return None,
+        };
+        let chars = self.chars().enumerate();
+        let mut res = 0_u32;
+        let mut offset = 0_usize;
+        for (i, c) in chars {
+            if i >= count {
+                break;
+            }
+            match c.to_digit(radix) {
+                Some(digit) => {
+                    let tmp = res * radix + digit;
+                    if tmp < 256 {
+                        res = tmp;
+                    } else {
+                        break;
+                    }
+                }
+                None => break,
+            }
+            offset = i + 1;
+        }
+        if offset > 0 {
+            Some((res as u8 as char, offset))
+        } else {
+            None
+        }
+    }
+}
+
+pub fn group_num(s: &str) -> Cow<str> {
+    assert!(s.chars().all(char::is_numeric));
+    if s.len() < 4 {
+        return s.into();
+    }
+    let mut res = String::with_capacity((s.len() - 1) / 3);
+    let mut alone = (s.len() - 1) % 3 + 1;
+    res.push_str(&s[..alone]);
+    while alone != s.len() {
+        res.push(',');
+        res.push_str(&s[alone..alone + 3]);
+        alone += 3;
+    }
+    res.into()
+}
+
+pub struct Stater {
+    follow: bool,
+    show_fs: bool,
+    from_user: bool,
+    files: Vec<String>,
+    mount_list: Option<Vec<String>>,
+    default_tokens: Vec<Token>,
+    default_dev_tokens: Vec<Token>,
+}
+
+#[allow(clippy::cognitive_complexity)]
+fn print_it(arg: &str, output_type: OutputType, flag: u8, width: usize, precision: i32) {
+    // If the precision is given as just '.', the precision is taken to be zero.
+    // A negative precision is taken as if the precision were omitted.
+    // This gives the minimum number of digits to appear for d, i, o, u, x, and X conversions,
+    // the maximum number of characters to be printed from a string for s and S conversions.
+
+    // #
+    // The value should be converted to an "alternate form".
+    // For o conversions, the first character of the output string  is made  zero  (by  prefixing  a 0 if it was not zero already).
+    // For x and X conversions, a nonzero result has the string "0x" (or "0X" for X conversions) prepended to it.
+
+    // 0
+    // The value should be zero padded.
+    // For d, i, o, u, x, X, a, A, e, E, f, F, g, and G conversions, the converted value is padded on the left with zeros rather than blanks.
+    // If the 0 and - flags both appear, the 0 flag is ignored.
+    // If a precision  is  given with a numeric conversion (d, i, o, u, x, and X), the 0 flag is ignored.
+    // For other conversions, the behavior is undefined.
+
+    // -
+    // The converted value is to be left adjusted on the field boundary.  (The default is right justification.)
+    // The  converted  value  is padded on the right with blanks, rather than on the left with blanks or zeros.
+    // A - overrides a 0 if both are given.
+
+    // ' ' (a space)
+    // A blank should be left before a positive number (or empty string) produced by a signed conversion.
+
+    // +
+    // A sign (+ or -) should always be placed before a number produced by a signed conversion.
+    // By default, a sign  is  used only for negative numbers.
+    // A + overrides a space if both are used.
+
+    if output_type == OutputType::Unknown {
+        return print!("?");
+    }
+
+    let left_align = has!(flag, F_LEFT);
+    let padding_char = if has!(flag, F_ZERO) && !left_align && precision == -1 {
+        '0'
+    } else {
+        ' '
+    };
+
+    let has_sign = has!(flag, F_SIGN) || has!(flag, F_SPACE);
+
+    let should_alter = has!(flag, F_ALTER);
+    let prefix = match output_type {
+        OutputType::UnsignedOct => "0",
+        OutputType::UnsignedHex => "0x",
+        OutputType::Integer => {
+            if has!(flag, F_SIGN) {
+                "+"
+            } else {
+                " "
+            }
+        }
+        _ => "",
+    };
+
+    match output_type {
+        OutputType::Str => {
+            let limit = cmp::min(precision, arg.len() as i32);
+            let s: &str = if limit >= 0 {
+                &arg[..limit as usize]
+            } else {
+                arg
+            };
+            print_adjusted!(s, left_align, width, ' ');
+        }
+        OutputType::Integer => {
+            let arg = if has!(flag, F_GROUP) {
+                group_num(arg)
+            } else {
+                Cow::Borrowed(arg)
+            };
+            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
+            let extended: Cow<str> = extend_digits!(arg.as_ref(), min_digits);
+            print_adjusted!(extended, left_align, has_sign, prefix, width, padding_char);
+        }
+        OutputType::Unsigned => {
+            let arg = if has!(flag, F_GROUP) {
+                group_num(arg)
+            } else {
+                Cow::Borrowed(arg)
+            };
+            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
+            let extended: Cow<str> = extend_digits!(arg.as_ref(), min_digits);
+            print_adjusted!(extended, left_align, width, padding_char);
+        }
+        OutputType::UnsignedOct => {
+            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
+            let extended: Cow<str> = extend_digits!(arg, min_digits);
+            print_adjusted!(
+                extended,
+                left_align,
+                should_alter,
+                prefix,
+                width,
+                padding_char
+            );
+        }
+        OutputType::UnsignedHex => {
+            let min_digits = cmp::max(precision, arg.len() as i32) as usize;
+            let extended: Cow<str> = extend_digits!(arg, min_digits);
+            print_adjusted!(
+                extended,
+                left_align,
+                should_alter,
+                prefix,
+                width,
+                padding_char
+            );
+        }
+        _ => unreachable!(),
+    }
+}
+
+impl Stater {
+    pub fn generate_tokens(format_str: &str, use_printf: bool) -> Result<Vec<Token>, String> {
+        let mut tokens = Vec::new();
+        let bound = format_str.len();
+        let chars = format_str.chars().collect::<Vec<char>>();
+        let mut i = 0_usize;
+        while i < bound {
+            match chars[i] {
+                '%' => {
+                    let old = i;
+
+                    i += 1;
+                    if i >= bound {
+                        tokens.push(Token::Char('%'));
+                        continue;
+                    }
+                    if chars[i] == '%' {
+                        tokens.push(Token::Char('%'));
+                        i += 1;
+                        continue;
+                    }
+
+                    let mut flag: u8 = 0;
+
+                    while i < bound {
+                        match chars[i] {
+                            '#' => flag |= F_ALTER,
+                            '0' => flag |= F_ZERO,
+                            '-' => flag |= F_LEFT,
+                            ' ' => flag |= F_SPACE,
+                            '+' => flag |= F_SIGN,
+                            '\'' => flag |= F_GROUP,
+                            'I' => unimplemented!(),
+                            _ => break,
+                        }
+                        i += 1;
+                    }
+                    check_bound!(format_str, bound, old, i);
+
+                    let mut width = 0_usize;
+                    let mut precision = -1_i32;
+                    let mut j = i;
+
+                    if let Some((field_width, offset)) = format_str[j..].scan_num::<usize>() {
+                        width = field_width;
+                        j += offset;
+                    }
+                    check_bound!(format_str, bound, old, j);
+
+                    if chars[j] == '.' {
+                        j += 1;
+                        check_bound!(format_str, bound, old, j);
+
+                        match format_str[j..].scan_num::<i32>() {
+                            Some((value, offset)) => {
+                                if value >= 0 {
+                                    precision = value;
+                                }
+                                j += offset;
+                            }
+                            None => precision = 0,
+                        }
+                        check_bound!(format_str, bound, old, j);
+                    }
+
+                    i = j;
+                    tokens.push(Token::Directive {
+                        width,
+                        flag,
+                        precision,
+                        format: chars[i],
+                    })
+                }
+                '\\' => {
+                    if !use_printf {
+                        tokens.push(Token::Char('\\'));
+                    } else {
+                        i += 1;
+                        if i >= bound {
+                            show_warning!("backslash at end of format");
+                            tokens.push(Token::Char('\\'));
+                            continue;
+                        }
+                        match chars[i] {
+                            'x' if i + 1 < bound => {
+                                if let Some((c, offset)) = format_str[i + 1..].scan_char(16) {
+                                    tokens.push(Token::Char(c));
+                                    i += offset;
+                                } else {
+                                    show_warning!("unrecognized escape '\\x'");
+                                    tokens.push(Token::Char('x'));
+                                }
+                            }
+                            '0'..='7' => {
+                                let (c, offset) = format_str[i..].scan_char(8).unwrap();
+                                tokens.push(Token::Char(c));
+                                i += offset - 1;
+                            }
+                            '"' => tokens.push(Token::Char('"')),
+                            '\\' => tokens.push(Token::Char('\\')),
+                            'a' => tokens.push(Token::Char('\x07')),
+                            'b' => tokens.push(Token::Char('\x08')),
+                            'e' => tokens.push(Token::Char('\x1B')),
+                            'f' => tokens.push(Token::Char('\x0C')),
+                            'n' => tokens.push(Token::Char('\n')),
+                            'r' => tokens.push(Token::Char('\r')),
+                            't' => tokens.push(Token::Char('\t')),
+                            'v' => tokens.push(Token::Char('\x0B')),
+                            c => {
+                                show_warning!("unrecognized escape '\\{}'", c);
+                                tokens.push(Token::Char(c));
+                            }
+                        }
+                    }
+                }
+
+                c => tokens.push(Token::Char(c)),
+            }
+            i += 1;
+        }
+        if !use_printf && !format_str.ends_with('\n') {
+            tokens.push(Token::Char('\n'));
+        }
+        Ok(tokens)
+    }
+
+    fn new(matches: ArgMatches) -> Result<Stater, String> {
+        let files: Vec<String> = matches
+            .values_of(ARG_FILES)
+            .map(|v| v.map(ToString::to_string).collect())
+            .unwrap_or_default();
+
+        let format_str = if matches.is_present(options::PRINTF) {
+            matches
+                .value_of(options::PRINTF)
+                .expect("Invalid format string")
+        } else {
+            matches.value_of(options::FORMAT).unwrap_or("")
+        };
+
+        let use_printf = matches.is_present(options::PRINTF);
+        let terse = matches.is_present(options::TERSE);
+        let show_fs = matches.is_present(options::FILE_SYSTEM);
+
+        let default_tokens = if format_str.is_empty() {
+            Stater::generate_tokens(&Stater::default_format(show_fs, terse, false), use_printf)
+                .unwrap()
+        } else {
+            Stater::generate_tokens(format_str, use_printf)?
+        };
+        let default_dev_tokens =
+            Stater::generate_tokens(&Stater::default_format(show_fs, terse, true), use_printf)
+                .unwrap();
+
+        let mount_list = if show_fs {
+            // mount points aren't displayed when showing filesystem information
+            None
+        } else {
+            let mut mount_list = read_fs_list()
+                .iter()
+                .map(|mi| mi.mount_dir.clone())
+                .collect::<Vec<String>>();
+            // Reverse sort. The longer comes first.
+            mount_list.sort();
+            mount_list.reverse();
+            Some(mount_list)
+        };
+
+        Ok(Stater {
+            follow: matches.is_present(options::DEREFERENCE),
+            show_fs,
+            from_user: !format_str.is_empty(),
+            files,
+            default_tokens,
+            default_dev_tokens,
+            mount_list,
+        })
+    }
+
+    fn find_mount_point<P: AsRef<Path>>(&self, p: P) -> Option<String> {
+        let path = match p.as_ref().canonicalize() {
+            Ok(s) => s,
+            Err(_) => return None,
+        };
+        if let Some(ref mount_list) = self.mount_list {
+            for root in mount_list.iter() {
+                if path.starts_with(root) {
+                    return Some(root.clone());
+                }
+            }
+        }
+        None
+    }
+
+    fn exec(&self) -> i32 {
+        let mut ret = 0;
+        for f in &self.files {
+            ret |= self.do_stat(f.as_str());
+        }
+        ret
+    }
+
+    fn do_stat(&self, file: &str) -> i32 {
+        if !self.show_fs {
+            let result = if self.follow {
+                fs::metadata(file)
+            } else {
+                fs::symlink_metadata(file)
+            };
+            match result {
+                Ok(meta) => {
+                    let file_type = meta.file_type();
+                    let tokens = if self.from_user
+                        || !(file_type.is_char_device() || file_type.is_block_device())
+                    {
+                        &self.default_tokens
+                    } else {
+                        &self.default_dev_tokens
+                    };
+
+                    for t in tokens.iter() {
+                        match *t {
+                            Token::Char(c) => print!("{}", c),
+                            Token::Directive {
+                                flag,
+                                width,
+                                precision,
+                                format,
+                            } => {
+                                let arg: String;
+                                let output_type: OutputType;
+
+                                match format {
+                                    // access rights in octal
+                                    'a' => {
+                                        arg = format!("{:o}", 0o7777 & meta.mode());
+                                        output_type = OutputType::UnsignedOct;
+                                    }
+                                    // access rights in human readable form
+                                    'A' => {
+                                        arg = display_permissions(&meta, true);
+                                        output_type = OutputType::Str;
+                                    }
+                                    // number of blocks allocated (see %B)
+                                    'b' => {
+                                        arg = format!("{}", meta.blocks());
+                                        output_type = OutputType::Unsigned;
+                                    }
+
+                                    // the size in bytes of each block reported by %b
+                                    // FIXME: blocksize differs on various platform
+                                    // See coreutils/gnulib/lib/stat-size.h ST_NBLOCKSIZE // spell-checker:disable-line
+                                    'B' => {
+                                        // the size in bytes of each block reported by %b
+                                        arg = format!("{}", 512);
+                                        output_type = OutputType::Unsigned;
+                                    }
+
+                                    // device number in decimal
+                                    'd' => {
+                                        arg = format!("{}", meta.dev());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // device number in hex
+                                    'D' => {
+                                        arg = format!("{:x}", meta.dev());
+                                        output_type = OutputType::UnsignedHex;
+                                    }
+                                    // raw mode in hex
+                                    'f' => {
+                                        arg = format!("{:x}", meta.mode());
+                                        output_type = OutputType::UnsignedHex;
+                                    }
+                                    // file type
+                                    'F' => {
+                                        arg = pretty_filetype(meta.mode() as mode_t, meta.len())
+                                            .to_owned();
+                                        output_type = OutputType::Str;
+                                    }
+                                    // group ID of owner
+                                    'g' => {
+                                        arg = format!("{}", meta.gid());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // group name of owner
+                                    'G' => {
+                                        arg = entries::gid2grp(meta.gid())
+                                            .unwrap_or_else(|_| "UNKNOWN".to_owned());
+                                        output_type = OutputType::Str;
+                                    }
+                                    // number of hard links
+                                    'h' => {
+                                        arg = format!("{}", meta.nlink());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // inode number
+                                    'i' => {
+                                        arg = format!("{}", meta.ino());
+                                        output_type = OutputType::Unsigned;
+                                    }
+
+                                    // mount point
+                                    'm' => {
+                                        arg = self.find_mount_point(file).unwrap();
+                                        output_type = OutputType::Str;
+                                    }
+
+                                    // file name
+                                    'n' => {
+                                        arg = file.to_owned();
+                                        output_type = OutputType::Str;
+                                    }
+                                    // quoted file name with dereference if symbolic link
+                                    'N' => {
+                                        if file_type.is_symlink() {
+                                            let dst = match fs::read_link(file) {
+                                                Ok(path) => path,
+                                                Err(e) => {
+                                                    println!("{}", e);
+                                                    return 1;
+                                                }
+                                            };
+                                            arg = format!(
+                                                "`{}' -> `{}'",
+                                                file,
+                                                dst.to_string_lossy()
+                                            );
+                                        } else {
+                                            arg = file.to_string();
+                                        }
+                                        output_type = OutputType::Str;
+                                    }
+                                    // optimal I/O transfer size hint
+                                    'o' => {
+                                        arg = format!("{}", meta.blksize());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // total size, in bytes
+                                    's' => {
+                                        arg = format!("{}", meta.len());
+                                        output_type = OutputType::Integer;
+                                    }
+                                    // major device type in hex, for character/block device special
+                                    // files
+                                    't' => {
+                                        arg = format!("{:x}", meta.rdev() >> 8);
+                                        output_type = OutputType::UnsignedHex;
+                                    }
+                                    // minor device type in hex, for character/block device special
+                                    // files
+                                    'T' => {
+                                        arg = format!("{:x}", meta.rdev() & 0xff);
+                                        output_type = OutputType::UnsignedHex;
+                                    }
+                                    // user ID of owner
+                                    'u' => {
+                                        arg = format!("{}", meta.uid());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // user name of owner
+                                    'U' => {
+                                        arg = entries::uid2usr(meta.uid())
+                                            .unwrap_or_else(|_| "UNKNOWN".to_owned());
+                                        output_type = OutputType::Str;
+                                    }
+
+                                    // time of file birth, human-readable; - if unknown
+                                    'w' => {
+                                        arg = meta.pretty_birth();
+                                        output_type = OutputType::Str;
+                                    }
+
+                                    // time of file birth, seconds since Epoch; 0 if unknown
+                                    'W' => {
+                                        arg = meta.birth();
+                                        output_type = OutputType::Integer;
+                                    }
+
+                                    // time of last access, human-readable
+                                    'x' => {
+                                        arg = pretty_time(meta.atime(), meta.atime_nsec());
+                                        output_type = OutputType::Str;
+                                    }
+                                    // time of last access, seconds since Epoch
+                                    'X' => {
+                                        arg = format!("{}", meta.atime());
+                                        output_type = OutputType::Integer;
+                                    }
+                                    // time of last data modification, human-readable
+                                    'y' => {
+                                        arg = pretty_time(meta.mtime(), meta.mtime_nsec());
+                                        output_type = OutputType::Str;
+                                    }
+                                    // time of last data modification, seconds since Epoch
+                                    'Y' => {
+                                        arg = format!("{}", meta.mtime());
+                                        output_type = OutputType::Str;
+                                    }
+                                    // time of last status change, human-readable
+                                    'z' => {
+                                        arg = pretty_time(meta.ctime(), meta.ctime_nsec());
+                                        output_type = OutputType::Str;
+                                    }
+                                    // time of last status change, seconds since Epoch
+                                    'Z' => {
+                                        arg = format!("{}", meta.ctime());
+                                        output_type = OutputType::Integer;
+                                    }
+
+                                    _ => {
+                                        arg = "?".to_owned();
+                                        output_type = OutputType::Unknown;
+                                    }
+                                }
+                                print_it(&arg, output_type, flag, width, precision);
+                            }
+                        }
+                    }
+                }
+                Err(e) => {
+                    show_error!("cannot stat '{}': {}", file, e);
+                    return 1;
+                }
+            }
+        } else {
+            match statfs(file) {
+                Ok(meta) => {
+                    let tokens = &self.default_tokens;
+
+                    for t in tokens.iter() {
+                        match *t {
+                            Token::Char(c) => print!("{}", c),
+                            Token::Directive {
+                                flag,
+                                width,
+                                precision,
+                                format,
+                            } => {
+                                let arg: String;
+                                let output_type: OutputType;
+                                match format {
+                                    // free blocks available to non-superuser
+                                    'a' => {
+                                        arg = format!("{}", meta.avail_blocks());
+                                        output_type = OutputType::Integer;
+                                    }
+                                    // total data blocks in file system
+                                    'b' => {
+                                        arg = format!("{}", meta.total_blocks());
+                                        output_type = OutputType::Integer;
+                                    }
+                                    // total file nodes in file system
+                                    'c' => {
+                                        arg = format!("{}", meta.total_file_nodes());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // free file nodes in file system
+                                    'd' => {
+                                        arg = format!("{}", meta.free_file_nodes());
+                                        output_type = OutputType::Integer;
+                                    }
+                                    // free blocks in file system
+                                    'f' => {
+                                        arg = format!("{}", meta.free_blocks());
+                                        output_type = OutputType::Integer;
+                                    }
+                                    // file system ID in hex
+                                    'i' => {
+                                        arg = format!("{:x}", meta.fsid());
+                                        output_type = OutputType::UnsignedHex;
+                                    }
+                                    // maximum length of filenames
+                                    'l' => {
+                                        arg = format!("{}", meta.namelen());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // file name
+                                    'n' => {
+                                        arg = file.to_owned();
+                                        output_type = OutputType::Str;
+                                    }
+                                    // block size (for faster transfers)
+                                    's' => {
+                                        arg = format!("{}", meta.io_size());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // fundamental block size (for block counts)
+                                    'S' => {
+                                        arg = format!("{}", meta.block_size());
+                                        output_type = OutputType::Unsigned;
+                                    }
+                                    // file system type in hex
+                                    't' => {
+                                        arg = format!("{:x}", meta.fs_type());
+                                        output_type = OutputType::UnsignedHex;
+                                    }
+                                    // file system type in human readable form
+                                    'T' => {
+                                        arg = pretty_fstype(meta.fs_type()).into_owned();
+                                        output_type = OutputType::Str;
+                                    }
+                                    _ => {
+                                        arg = "?".to_owned();
+                                        output_type = OutputType::Unknown;
+                                    }
+                                }
+
+                                print_it(&arg, output_type, flag, width, precision);
+                            }
+                        }
+                    }
+                }
+                Err(e) => {
+                    show_error!("cannot read file system information for '{}': {}", file, e);
+                    return 1;
+                }
+            }
+        }
+        0
+    }
+
+    fn default_format(show_fs: bool, terse: bool, show_dev_type: bool) -> String {
+        // SELinux related format is *ignored*
+
+        let mut format_str = String::with_capacity(36);
+        if show_fs {
+            if terse {
+                format_str.push_str("%n %i %l %t %s %S %b %f %a %c %d\n");
+            } else {
+                format_str.push_str(
+                    "  File: \"%n\"\n    ID: %-8i Namelen: %-7l Type: %T\nBlock \
+                     size: %-10s Fundamental block size: %S\nBlocks: Total: %-10b \
+                     Free: %-10f Available: %a\nInodes: Total: %-10c Free: %d\n",
+                );
+            }
+        } else if terse {
+            format_str.push_str("%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %W %o\n");
+        } else {
+            format_str.push_str("  File: %N\n  Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n");
+            if show_dev_type {
+                format_str
+                    .push_str("Device: %Dh/%dd\tInode: %-10i  Links: %-5h Device type: %t,%T\n");
+            } else {
+                format_str.push_str("Device: %Dh/%dd\tInode: %-10i  Links: %h\n");
+            }
+            format_str.push_str("Access: (%04a/%10.10A)  Uid: (%5u/%8U)   Gid: (%5g/%8G)\n");
+            format_str.push_str("Access: %x\nModify: %y\nChange: %z\n Birth: %w\n");
+        }
+        format_str
+    }
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    String::from(
+        "
+The valid format sequences for files (without --file-system):
+
+  %a   access rights in octal (note '#' and '0' printf flags)
+  %A   access rights in human readable form
+  %b   number of blocks allocated (see %B)
+  %B   the size in bytes of each block reported by %b
+  %C   SELinux security context string
+  %d   device number in decimal
+  %D   device number in hex
+  %f   raw mode in hex
+  %F   file type
+  %g   group ID of owner
+  %G   group name of owner
+  %h   number of hard links
+  %i   inode number
+  %m   mount point
+  %n   file name
+  %N   quoted file name with dereference if symbolic link
+  %o   optimal I/O transfer size hint
+  %s   total size, in bytes
+  %t   major device type in hex, for character/block device special files
+  %T   minor device type in hex, for character/block device special files
+  %u   user ID of owner
+  %U   user name of owner
+  %w   time of file birth, human-readable; - if unknown
+  %W   time of file birth, seconds since Epoch; 0 if unknown
+  %x   time of last access, human-readable
+  %X   time of last access, seconds since Epoch
+  %y   time of last data modification, human-readable
+  %Y   time of last data modification, seconds since Epoch
+  %z   time of last status change, human-readable
+  %Z   time of last status change, seconds since Epoch
+
+Valid format sequences for file systems:
+
+  %a   free blocks available to non-superuser
+  %b   total data blocks in file system
+  %c   total file nodes in file system
+  %d   free file nodes in file system
+  %f   free blocks in file system
+  %i   file system ID in hex
+  %l   maximum length of filenames
+  %n   file name
+  %s   block size (for faster transfers)
+  %S   fundamental block size (for block counts)
+  %t   file system type in hex
+  %T   file system type in human readable form
+
+NOTE: your shell may have its own version of stat, which usually supersedes
+the version described here.  Please refer to your shell's documentation
+for details about the options it supports.
+",
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let long_usage = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&long_usage[..])
+        .get_matches_from(args);
+
+    match Stater::new(matches) {
+        Ok(stater) => stater.exec(),
+        Err(e) => {
+            show_error!("{}", e);
+            1
+        }
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::DEREFERENCE)
+                .short("L")
+                .long(options::DEREFERENCE)
+                .help("follow links"),
+        )
+        .arg(
+            Arg::with_name(options::FILE_SYSTEM)
+                .short("f")
+                .long(options::FILE_SYSTEM)
+                .help("display file system status instead of file status"),
+        )
+        .arg(
+            Arg::with_name(options::TERSE)
+                .short("t")
+                .long(options::TERSE)
+                .help("print the information in terse form"),
+        )
+        .arg(
+            Arg::with_name(options::FORMAT)
+                .short("c")
+                .long(options::FORMAT)
+                .help(
+                    "use the specified FORMAT instead of the default;
+ output a newline after each use of FORMAT",
+                )
+                .value_name("FORMAT"),
+        )
+        .arg(
+            Arg::with_name(options::PRINTF)
+                .long(options::PRINTF)
+                .value_name("FORMAT")
+                .help(
+                    "like --format, but interpret backslash escapes,
+            and do not output a mandatory trailing newline;
+            if you want a newline, include \n in FORMAT",
+                ),
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_stdbuf/stdbuf.rs.html b/src/uu_stdbuf/stdbuf.rs.html new file mode 100644 index 000000000..c87daca27 --- /dev/null +++ b/src/uu_stdbuf/stdbuf.rs.html @@ -0,0 +1,465 @@ +stdbuf.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) Dorota Kapturkiewicz <dokaptur@gmail.com>
+// *
+// * For the full copyright and license information, please view the LICENSE
+// * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) tempdir dyld dylib dragonflybsd optgrps libstdbuf
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
+use std::convert::TryFrom;
+use std::fs::File;
+use std::io::{self, Write};
+use std::os::unix::process::ExitStatusExt;
+use std::path::PathBuf;
+use std::process::Command;
+use tempfile::tempdir;
+use tempfile::TempDir;
+use uucore::parse_size::parse_size;
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str =
+    "Run COMMAND, with modified buffering operations for its standard streams.\n\n\
+     Mandatory arguments to long options are mandatory for short options too.";
+static LONG_HELP: &str = "If MODE is 'L' the corresponding stream will be line buffered.\n\
+     This option is invalid with standard input.\n\n\
+     If MODE is '0' the corresponding stream will be unbuffered.\n\n\
+     Otherwise MODE is a number which may be followed by one of the following:\n\n\
+     KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.\n\
+     In this case the corresponding stream will be fully buffered with the buffer size set to \
+     MODE bytes.\n\n\
+     NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for e.g.) then \
+     that will override corresponding settings changed by 'stdbuf'.\n\
+     Also some filters (like 'dd' and 'cat' etc.) don't use streams for I/O, \
+     and are thus unaffected by 'stdbuf' settings.\n";
+
+mod options {
+    pub const INPUT: &str = "input";
+    pub const INPUT_SHORT: &str = "i";
+    pub const OUTPUT: &str = "output";
+    pub const OUTPUT_SHORT: &str = "o";
+    pub const ERROR: &str = "error";
+    pub const ERROR_SHORT: &str = "e";
+    pub const COMMAND: &str = "command";
+}
+
+fn usage() -> String {
+    format!("{0} OPTION... COMMAND", uucore::execution_phrase())
+}
+
+const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.so"));
+
+enum BufferType {
+    Default,
+    Line,
+    Size(usize),
+}
+
+struct ProgramOptions {
+    stdin: BufferType,
+    stdout: BufferType,
+    stderr: BufferType,
+}
+
+impl<'a> TryFrom<&ArgMatches<'a>> for ProgramOptions {
+    type Error = ProgramOptionsError;
+
+    fn try_from(matches: &ArgMatches) -> Result<Self, Self::Error> {
+        Ok(ProgramOptions {
+            stdin: check_option(matches, options::INPUT)?,
+            stdout: check_option(matches, options::OUTPUT)?,
+            stderr: check_option(matches, options::ERROR)?,
+        })
+    }
+}
+
+struct ProgramOptionsError(String);
+
+#[cfg(any(
+    target_os = "linux",
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "dragonflybsd"
+))]
+fn preload_strings() -> (&'static str, &'static str) {
+    ("LD_PRELOAD", "so")
+}
+
+#[cfg(target_vendor = "apple")]
+fn preload_strings() -> (&'static str, &'static str) {
+    ("DYLD_LIBRARY_PATH", "dylib")
+}
+
+#[cfg(not(any(
+    target_os = "linux",
+    target_os = "freebsd",
+    target_os = "netbsd",
+    target_os = "dragonflybsd",
+    target_vendor = "apple"
+)))]
+fn preload_strings() -> (&'static str, &'static str) {
+    crash!(1, "Command not supported for this operating system!")
+}
+
+fn check_option(matches: &ArgMatches, name: &str) -> Result<BufferType, ProgramOptionsError> {
+    match matches.value_of(name) {
+        Some(value) => match value {
+            "L" => {
+                if name == options::INPUT {
+                    Err(ProgramOptionsError(
+                        "line buffering stdin is meaningless".to_string(),
+                    ))
+                } else {
+                    Ok(BufferType::Line)
+                }
+            }
+            x => parse_size(x).map_or_else(
+                |e| crash!(125, "invalid mode {}", e),
+                |m| Ok(BufferType::Size(m)),
+            ),
+        },
+        None => Ok(BufferType::Default),
+    }
+}
+
+fn set_command_env(command: &mut Command, buffer_name: &str, buffer_type: BufferType) {
+    match buffer_type {
+        BufferType::Size(m) => {
+            command.env(buffer_name, m.to_string());
+        }
+        BufferType::Line => {
+            command.env(buffer_name, "L");
+        }
+        BufferType::Default => {}
+    }
+}
+
+fn get_preload_env(tmp_dir: &mut TempDir) -> io::Result<(String, PathBuf)> {
+    let (preload, extension) = preload_strings();
+    let inject_path = tmp_dir.path().join("libstdbuf").with_extension(extension);
+
+    let mut file = File::create(&inject_path)?;
+    file.write_all(STDBUF_INJECT)?;
+
+    Ok((preload.to_owned(), inject_path))
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let options = ProgramOptions::try_from(&matches).unwrap_or_else(|e| {
+        crash!(
+            125,
+            "{}\nTry '{} --help' for more information.",
+            e.0,
+            uucore::execution_phrase()
+        )
+    });
+
+    let mut command_values = matches.values_of::<&str>(options::COMMAND).unwrap();
+    let mut command = Command::new(command_values.next().unwrap());
+    let command_params: Vec<&str> = command_values.collect();
+
+    let mut tmp_dir = tempdir().unwrap();
+    let (preload_env, libstdbuf) = return_if_err!(1, get_preload_env(&mut tmp_dir));
+    command.env(preload_env, libstdbuf);
+    set_command_env(&mut command, "_STDBUF_I", options.stdin);
+    set_command_env(&mut command, "_STDBUF_O", options.stdout);
+    set_command_env(&mut command, "_STDBUF_E", options.stderr);
+    command.args(command_params);
+
+    let mut process = match command.spawn() {
+        Ok(p) => p,
+        Err(e) => crash!(1, "failed to execute process: {}", e),
+    };
+    match process.wait() {
+        Ok(status) => match status.code() {
+            Some(i) => i,
+            None => crash!(1, "process killed by signal {}", status.signal().unwrap()),
+        },
+        Err(e) => crash!(1, "{}", e),
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help(LONG_HELP)
+        .setting(AppSettings::TrailingVarArg)
+        .arg(
+            Arg::with_name(options::INPUT)
+                .long(options::INPUT)
+                .short(options::INPUT_SHORT)
+                .help("adjust standard input stream buffering")
+                .value_name("MODE")
+                .required_unless_one(&[options::OUTPUT, options::ERROR]),
+        )
+        .arg(
+            Arg::with_name(options::OUTPUT)
+                .long(options::OUTPUT)
+                .short(options::OUTPUT_SHORT)
+                .help("adjust standard output stream buffering")
+                .value_name("MODE")
+                .required_unless_one(&[options::INPUT, options::ERROR]),
+        )
+        .arg(
+            Arg::with_name(options::ERROR)
+                .long(options::ERROR)
+                .short(options::ERROR_SHORT)
+                .help("adjust standard error stream buffering")
+                .value_name("MODE")
+                .required_unless_one(&[options::INPUT, options::OUTPUT]),
+        )
+        .arg(
+            Arg::with_name(options::COMMAND)
+                .multiple(true)
+                .takes_value(true)
+                .hidden(true)
+                .required(true),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_sum/sum.rs.html b/src/uu_sum/sum.rs.html new file mode 100644 index 000000000..da9e70d48 --- /dev/null +++ b/src/uu_sum/sum.rs.html @@ -0,0 +1,325 @@ +sum.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+
+// * This file is part of the uutils coreutils package.
+// *
+// * (c) T. Jameson Little <t.jameson.little@gmail.com>
+// *
+// * For the full copyright and license information, please view the LICENSE file
+// * that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) sysv
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{stdin, Read, Result};
+use std::path::Path;
+use uucore::InvalidEncodingHandling;
+
+static NAME: &str = "sum";
+static USAGE: &str =
+    "[OPTION]... [FILE]...\nWith no FILE, or when  FILE is -, read standard input.";
+static SUMMARY: &str = "Checksum and count the blocks in a file.";
+
+fn bsd_sum(mut reader: Box<dyn Read>) -> (usize, u16) {
+    let mut buf = [0; 1024];
+    let mut blocks_read = 0;
+    let mut checksum: u16 = 0;
+    loop {
+        match reader.read(&mut buf) {
+            Ok(n) if n != 0 => {
+                blocks_read += 1;
+                for &byte in buf[..n].iter() {
+                    checksum = (checksum >> 1) + ((checksum & 1) << 15);
+                    checksum = checksum.wrapping_add(u16::from(byte));
+                }
+            }
+            _ => break,
+        }
+    }
+
+    (blocks_read, checksum)
+}
+
+fn sysv_sum(mut reader: Box<dyn Read>) -> (usize, u16) {
+    let mut buf = [0; 512];
+    let mut blocks_read = 0;
+    let mut ret = 0u32;
+
+    loop {
+        match reader.read(&mut buf) {
+            Ok(n) if n != 0 => {
+                blocks_read += 1;
+                for &byte in buf[..n].iter() {
+                    ret = ret.wrapping_add(u32::from(byte));
+                }
+            }
+            _ => break,
+        }
+    }
+
+    ret = (ret & 0xffff) + (ret >> 16);
+    ret = (ret & 0xffff) + (ret >> 16);
+
+    (blocks_read, ret as u16)
+}
+
+fn open(name: &str) -> Result<Box<dyn Read>> {
+    match name {
+        "-" => Ok(Box::new(stdin()) as Box<dyn Read>),
+        _ => {
+            let path = &Path::new(name);
+            if path.is_dir() {
+                return Err(std::io::Error::new(
+                    std::io::ErrorKind::InvalidInput,
+                    "Is a directory",
+                ));
+            };
+            if path.metadata().is_err() {
+                return Err(std::io::Error::new(
+                    std::io::ErrorKind::NotFound,
+                    "No such file or directory",
+                ));
+            };
+            let f = File::open(path)?;
+            Ok(Box::new(f) as Box<dyn Read>)
+        }
+    }
+}
+
+mod options {
+    pub static FILE: &str = "file";
+    pub static BSD_COMPATIBLE: &str = "r";
+    pub static SYSTEM_V_COMPATIBLE: &str = "sysv";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let files: Vec<String> = match matches.values_of(options::FILE) {
+        Some(v) => v.clone().map(|v| v.to_owned()).collect(),
+        None => vec!["-".to_owned()],
+    };
+
+    let sysv = matches.is_present(options::SYSTEM_V_COMPATIBLE);
+
+    let print_names = if sysv {
+        files.len() > 1 || files[0] != "-"
+    } else {
+        files.len() > 1
+    };
+
+    let mut exit_code = 0;
+    for file in &files {
+        let reader = match open(file) {
+            Ok(f) => f,
+            Err(error) => {
+                show_error!("'{}' {}", file, error);
+                exit_code = 2;
+                continue;
+            }
+        };
+        let (blocks, sum) = if sysv {
+            sysv_sum(reader)
+        } else {
+            bsd_sum(reader)
+        };
+
+        if print_names {
+            println!("{} {} {}", sum, blocks, file);
+        } else {
+            println!("{} {}", sum, blocks);
+        }
+    }
+
+    exit_code
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(USAGE)
+        .about(SUMMARY)
+        .arg(Arg::with_name(options::FILE).multiple(true).hidden(true))
+        .arg(
+            Arg::with_name(options::BSD_COMPATIBLE)
+                .short(options::BSD_COMPATIBLE)
+                .help("use the BSD sum algorithm, use 1K blocks (default)"),
+        )
+        .arg(
+            Arg::with_name(options::SYSTEM_V_COMPATIBLE)
+                .short("s")
+                .long(options::SYSTEM_V_COMPATIBLE)
+                .help("use System V sum algorithm, use 512 bytes blocks"),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_sync/sync.rs.html b/src/uu_sync/sync.rs.html new file mode 100644 index 000000000..c4acc8be4 --- /dev/null +++ b/src/uu_sync/sync.rs.html @@ -0,0 +1,461 @@ +sync.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alexander Fomin <xander.fomin@ya.ru>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+/* Last synced with: sync (GNU coreutils) 8.13 */
+
+extern crate libc;
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::path::Path;
+
+static EXIT_ERR: i32 = 1;
+
+static ABOUT: &str = "Synchronize cached writes to persistent storage";
+pub mod options {
+    pub static FILE_SYSTEM: &str = "file-system";
+    pub static DATA: &str = "data";
+}
+
+static ARG_FILES: &str = "files";
+
+#[cfg(unix)]
+mod platform {
+    use super::libc;
+    #[cfg(target_os = "linux")]
+    use std::fs::File;
+    #[cfg(target_os = "linux")]
+    use std::os::unix::io::AsRawFd;
+
+    pub unsafe fn do_sync() -> isize {
+        libc::sync();
+        0
+    }
+
+    #[cfg(target_os = "linux")]
+    pub unsafe fn do_syncfs(files: Vec<String>) -> isize {
+        for path in files {
+            let f = File::open(&path).unwrap();
+            let fd = f.as_raw_fd();
+            libc::syscall(libc::SYS_syncfs, fd);
+        }
+        0
+    }
+
+    #[cfg(target_os = "linux")]
+    pub unsafe fn do_fdatasync(files: Vec<String>) -> isize {
+        for path in files {
+            let f = File::open(&path).unwrap();
+            let fd = f.as_raw_fd();
+            libc::syscall(libc::SYS_fdatasync, fd);
+        }
+        0
+    }
+}
+
+#[cfg(windows)]
+mod platform {
+    extern crate winapi;
+    use self::winapi::shared::minwindef;
+    use self::winapi::shared::winerror;
+    use self::winapi::um::handleapi;
+    use self::winapi::um::winbase;
+    use self::winapi::um::winnt;
+    use std::fs::OpenOptions;
+    use std::mem;
+    use std::os::windows::prelude::*;
+    use std::path::Path;
+    use uucore::wide::{FromWide, ToWide};
+
+    unsafe fn flush_volume(name: &str) {
+        let name_wide = name.to_wide_null();
+        if winapi::um::fileapi::GetDriveTypeW(name_wide.as_ptr()) == winbase::DRIVE_FIXED {
+            let sliced_name = &name[..name.len() - 1]; // eliminate trailing backslash
+            match OpenOptions::new().write(true).open(sliced_name) {
+                Ok(file) => {
+                    if winapi::um::fileapi::FlushFileBuffers(file.as_raw_handle()) == 0 {
+                        crash!(
+                            winapi::um::errhandlingapi::GetLastError() as i32,
+                            "failed to flush file buffer"
+                        );
+                    }
+                }
+                Err(e) => crash!(
+                    e.raw_os_error().unwrap_or(1),
+                    "failed to create volume handle"
+                ),
+            }
+        }
+    }
+
+    unsafe fn find_first_volume() -> (String, winnt::HANDLE) {
+        #[allow(deprecated)]
+        let mut name: [winnt::WCHAR; minwindef::MAX_PATH] = mem::uninitialized();
+        let handle = winapi::um::fileapi::FindFirstVolumeW(
+            name.as_mut_ptr(),
+            name.len() as minwindef::DWORD,
+        );
+        if handle == handleapi::INVALID_HANDLE_VALUE {
+            crash!(
+                winapi::um::errhandlingapi::GetLastError() as i32,
+                "failed to find first volume"
+            );
+        }
+        (String::from_wide_null(&name), handle)
+    }
+
+    unsafe fn find_all_volumes() -> Vec<String> {
+        let (first_volume, next_volume_handle) = find_first_volume();
+        let mut volumes = vec![first_volume];
+        loop {
+            #[allow(deprecated)]
+            let mut name: [winnt::WCHAR; minwindef::MAX_PATH] = mem::uninitialized();
+            if winapi::um::fileapi::FindNextVolumeW(
+                next_volume_handle,
+                name.as_mut_ptr(),
+                name.len() as minwindef::DWORD,
+            ) == 0
+            {
+                match winapi::um::errhandlingapi::GetLastError() {
+                    winerror::ERROR_NO_MORE_FILES => {
+                        winapi::um::fileapi::FindVolumeClose(next_volume_handle);
+                        return volumes;
+                    }
+                    err => crash!(err as i32, "failed to find next volume"),
+                }
+            } else {
+                volumes.push(String::from_wide_null(&name));
+            }
+        }
+    }
+
+    pub unsafe fn do_sync() -> isize {
+        let volumes = find_all_volumes();
+        for vol in &volumes {
+            flush_volume(vol);
+        }
+        0
+    }
+
+    pub unsafe fn do_syncfs(files: Vec<String>) -> isize {
+        for path in files {
+            flush_volume(
+                Path::new(&path)
+                    .components()
+                    .next()
+                    .unwrap()
+                    .as_os_str()
+                    .to_str()
+                    .unwrap(),
+            );
+        }
+        0
+    }
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    for f in &files {
+        if !Path::new(&f).exists() {
+            crash!(EXIT_ERR, "cannot stat '{}': No such file or directory", f);
+        }
+    }
+
+    #[allow(clippy::if_same_then_else)]
+    if matches.is_present(options::FILE_SYSTEM) {
+        #[cfg(any(target_os = "linux", target_os = "windows"))]
+        syncfs(files);
+    } else if matches.is_present(options::DATA) {
+        #[cfg(target_os = "linux")]
+        fdatasync(files);
+    } else {
+        sync();
+    }
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::FILE_SYSTEM)
+                .short("f")
+                .long(options::FILE_SYSTEM)
+                .conflicts_with(options::DATA)
+                .help("sync the file systems that contain the files (Linux and Windows only)"),
+        )
+        .arg(
+            Arg::with_name(options::DATA)
+                .short("d")
+                .long(options::DATA)
+                .conflicts_with(options::FILE_SYSTEM)
+                .help("sync only file data, no unneeded metadata (Linux only)"),
+        )
+        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
+}
+
+fn sync() -> isize {
+    unsafe { platform::do_sync() }
+}
+
+#[cfg(any(target_os = "linux", target_os = "windows"))]
+fn syncfs(files: Vec<String>) -> isize {
+    unsafe { platform::do_syncfs(files) }
+}
+
+#[cfg(target_os = "linux")]
+fn fdatasync(files: Vec<String>) -> isize {
+    unsafe { platform::do_fdatasync(files) }
+}
+
+
\ No newline at end of file diff --git a/src/uu_tac/tac.rs.html b/src/uu_tac/tac.rs.html new file mode 100644 index 000000000..1896a1ff4 --- /dev/null +++ b/src/uu_tac/tac.rs.html @@ -0,0 +1,355 @@ +tac.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) sbytes slen dlen memmem
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use memchr::memmem;
+use std::io::{stdin, stdout, BufReader, Read, Write};
+use std::{fs::File, path::Path};
+use uucore::InvalidEncodingHandling;
+
+static NAME: &str = "tac";
+static USAGE: &str = "[OPTION]... [FILE]...";
+static SUMMARY: &str = "Write each file to standard output, last line first.";
+
+mod options {
+    pub static BEFORE: &str = "before";
+    pub static REGEX: &str = "regex";
+    pub static SEPARATOR: &str = "separator";
+    pub static FILE: &str = "file";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let before = matches.is_present(options::BEFORE);
+    let regex = matches.is_present(options::REGEX);
+    let raw_separator = matches.value_of(options::SEPARATOR).unwrap_or("\n");
+    let separator = if raw_separator.is_empty() {
+        "\0"
+    } else {
+        raw_separator
+    };
+
+    let files: Vec<String> = match matches.values_of(options::FILE) {
+        Some(v) => v.map(|v| v.to_owned()).collect(),
+        None => vec!["-".to_owned()],
+    };
+
+    tac(files, before, regex, separator)
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(USAGE)
+        .about(SUMMARY)
+        .arg(
+            Arg::with_name(options::BEFORE)
+                .short("b")
+                .long(options::BEFORE)
+                .help("attach the separator before instead of after")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::REGEX)
+                .short("r")
+                .long(options::REGEX)
+                .help("interpret the sequence as a regular expression (NOT IMPLEMENTED)")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::SEPARATOR)
+                .short("s")
+                .long(options::SEPARATOR)
+                .help("use STRING as the separator instead of newline")
+                .takes_value(true),
+        )
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+}
+
+/// Write lines from `data` to stdout in reverse.
+///
+/// This function writes to [`stdout`] each line appearing in `data`,
+/// starting with the last line and ending with the first line. The
+/// `separator` parameter defines what characters to use as a line
+/// separator.
+///
+/// If `before` is `false`, then this function assumes that the
+/// `separator` appears at the end of each line, as in `"abc\ndef\n"`.
+/// If `before` is `true`, then this function assumes that the
+/// `separator` appears at the beginning of each line, as in
+/// `"/abc/def"`.
+fn buffer_tac(data: &[u8], before: bool, separator: &str) -> std::io::Result<()> {
+    let mut out = stdout();
+
+    // The number of bytes in the line separator.
+    let slen = separator.as_bytes().len();
+
+    // The index of the start of the next line in the `data`.
+    //
+    // As we scan through the `data` from right to left, we update this
+    // variable each time we find a new line.
+    //
+    // If `before` is `true`, then each line starts immediately before
+    // the line separator. Otherwise, each line starts immediately after
+    // the line separator.
+    let mut following_line_start = data.len();
+
+    // Iterate over each byte in the buffer in reverse. When we find a
+    // line separator, write the line to stdout.
+    //
+    // The `before` flag controls whether the line separator appears at
+    // the end of the line (as in "abc\ndef\n") or at the beginning of
+    // the line (as in "/abc/def").
+    for i in memmem::rfind_iter(data, separator) {
+        if before {
+            out.write_all(&data[i..following_line_start])?;
+            following_line_start = i;
+        } else {
+            out.write_all(&data[i + slen..following_line_start])?;
+            following_line_start = i + slen;
+        }
+    }
+
+    // After the loop terminates, write whatever bytes are remaining at
+    // the beginning of the buffer.
+    out.write_all(&data[0..following_line_start])?;
+    Ok(())
+}
+
+fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
+    let mut exit_code = 0;
+
+    for filename in &filenames {
+        let mut file = BufReader::new(if filename == "-" {
+            Box::new(stdin()) as Box<dyn Read>
+        } else {
+            let path = Path::new(filename);
+            if path.is_dir() || path.metadata().is_err() {
+                if path.is_dir() {
+                    show_error!("{}: read error: Invalid argument", filename);
+                } else {
+                    show_error!(
+                        "failed to open '{}' for reading: No such file or directory",
+                        filename
+                    );
+                }
+                exit_code = 1;
+                continue;
+            }
+            match File::open(path) {
+                Ok(f) => Box::new(f) as Box<dyn Read>,
+                Err(e) => {
+                    show_error!("failed to open '{}' for reading: {}", filename, e);
+                    exit_code = 1;
+                    continue;
+                }
+            }
+        });
+
+        let mut data = Vec::new();
+        if let Err(e) = file.read_to_end(&mut data) {
+            show_error!("failed to read '{}': {}", filename, e);
+            exit_code = 1;
+            continue;
+        };
+
+        buffer_tac(&data, before, separator)
+            .unwrap_or_else(|e| crash!(1, "failed to write to stdout: {}", e));
+    }
+    exit_code
+}
+
+
\ No newline at end of file diff --git a/src/uu_tail/chunks.rs.html b/src/uu_tail/chunks.rs.html new file mode 100644 index 000000000..8816f9a4e --- /dev/null +++ b/src/uu_tail/chunks.rs.html @@ -0,0 +1,171 @@ +chunks.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+
+//! Iterating over a file by chunks, starting at the end of the file.
+//!
+//! Use [`ReverseChunks::new`] to create a new iterator over chunks of
+//! bytes from the file.
+use std::fs::File;
+use std::io::{Read, Seek, SeekFrom};
+
+/// When reading files in reverse in `bounded_tail`, this is the size of each
+/// block read at a time.
+pub const BLOCK_SIZE: u64 = 1 << 16;
+
+/// An iterator over a file in non-overlapping chunks from the end of the file.
+///
+/// Each chunk is a [`Vec`]<[`u8`]> of size [`BLOCK_SIZE`] (except
+/// possibly the last chunk, which might be smaller). Each call to
+/// [`next`] will seek backwards through the given file.
+pub struct ReverseChunks<'a> {
+    /// The file to iterate over, by blocks, from the end to the beginning.
+    file: &'a File,
+
+    /// The total number of bytes in the file.
+    size: u64,
+
+    /// The total number of blocks to read.
+    max_blocks_to_read: usize,
+
+    /// The index of the next block to read.
+    block_idx: usize,
+}
+
+impl<'a> ReverseChunks<'a> {
+    pub fn new(file: &'a mut File) -> ReverseChunks<'a> {
+        let size = file.seek(SeekFrom::End(0)).unwrap();
+        let max_blocks_to_read = (size as f64 / BLOCK_SIZE as f64).ceil() as usize;
+        let block_idx = 0;
+        ReverseChunks {
+            file,
+            size,
+            max_blocks_to_read,
+            block_idx,
+        }
+    }
+}
+
+impl<'a> Iterator for ReverseChunks<'a> {
+    type Item = Vec<u8>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        // If there are no more chunks to read, terminate the iterator.
+        if self.block_idx >= self.max_blocks_to_read {
+            return None;
+        }
+
+        // The chunk size is `BLOCK_SIZE` for all but the last chunk
+        // (that is, the chunk closest to the beginning of the file),
+        // which contains the remainder of the bytes.
+        let block_size = if self.block_idx == self.max_blocks_to_read - 1 {
+            self.size % BLOCK_SIZE
+        } else {
+            BLOCK_SIZE
+        };
+
+        // Seek backwards by the next chunk, read the full chunk into
+        // `buf`, and then seek back to the start of the chunk again.
+        let mut buf = vec![0; BLOCK_SIZE as usize];
+        let pos = self
+            .file
+            .seek(SeekFrom::Current(-(block_size as i64)))
+            .unwrap();
+        self.file
+            .read_exact(&mut buf[0..(block_size as usize)])
+            .unwrap();
+        let pos2 = self
+            .file
+            .seek(SeekFrom::Current(-(block_size as i64)))
+            .unwrap();
+        assert_eq!(pos, pos2);
+
+        self.block_idx += 1;
+
+        Some(buf[0..(block_size as usize)].to_vec())
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_tail/platform/mod.rs.html b/src/uu_tail/platform/mod.rs.html new file mode 100644 index 000000000..f43789ea7 --- /dev/null +++ b/src/uu_tail/platform/mod.rs.html @@ -0,0 +1,47 @@ +mod.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+
+/*
+ * This file is part of the uutils coreutils package.
+ *
+ * (c) Alexander Batischev <eual.jp@gmail.com>
+ * (c) Thomas Queiroz <thomasqueirozb@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+#[cfg(unix)]
+pub use self::unix::{stdin_is_pipe_or_fifo, supports_pid_checks, Pid, ProcessChecker};
+
+#[cfg(windows)]
+pub use self::windows::{supports_pid_checks, Pid, ProcessChecker};
+
+#[cfg(unix)]
+mod unix;
+
+#[cfg(windows)]
+mod windows;
+
+
\ No newline at end of file diff --git a/src/uu_tail/platform/unix.rs.html b/src/uu_tail/platform/unix.rs.html new file mode 100644 index 000000000..9d21f0a23 --- /dev/null +++ b/src/uu_tail/platform/unix.rs.html @@ -0,0 +1,129 @@ +unix.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+
+/*
+ * This file is part of the uutils coreutils package.
+ *
+ * (c) Alexander Batischev <eual.jp@gmail.com>
+ * (c) Thomas Queiroz <thomasqueirozb@gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+// spell-checker:ignore (ToDO) errno EPERM ENOSYS
+
+use std::io::{stdin, Error};
+
+use std::os::unix::prelude::AsRawFd;
+
+use nix::sys::stat::fstat;
+
+use libc::{S_IFIFO, S_IFSOCK};
+
+pub type Pid = libc::pid_t;
+
+pub struct ProcessChecker {
+    pid: self::Pid,
+}
+
+impl ProcessChecker {
+    pub fn new(process_id: self::Pid) -> ProcessChecker {
+        ProcessChecker { pid: process_id }
+    }
+
+    // Borrowing mutably to be aligned with Windows implementation
+    pub fn is_dead(&mut self) -> bool {
+        unsafe { libc::kill(self.pid, 0) != 0 && get_errno() != libc::EPERM }
+    }
+}
+
+impl Drop for ProcessChecker {
+    fn drop(&mut self) {}
+}
+
+pub fn supports_pid_checks(pid: self::Pid) -> bool {
+    unsafe { !(libc::kill(pid, 0) != 0 && get_errno() == libc::ENOSYS) }
+}
+
+#[inline]
+fn get_errno() -> i32 {
+    Error::last_os_error().raw_os_error().unwrap()
+}
+
+pub fn stdin_is_pipe_or_fifo() -> bool {
+    let fd = stdin().lock().as_raw_fd();
+    fd >= 0 // GNU tail checks fd >= 0
+                            && match fstat(fd) {
+                                Ok(stat) => {
+                                    let mode = stat.st_mode;
+                                    // NOTE: This is probably not the most correct way to check this
+                                    (mode & S_IFIFO != 0) || (mode & S_IFSOCK != 0)
+                                }
+                                Err(err) => panic!("{}", err),
+                            }
+}
+
+
\ No newline at end of file diff --git a/src/uu_tail/tail.rs.html b/src/uu_tail/tail.rs.html new file mode 100644 index 000000000..d3fd97bae --- /dev/null +++ b/src/uu_tail/tail.rs.html @@ -0,0 +1,937 @@ +tail.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Morten Olsen Lysgaard <morten@lysgaard.no>
+//  * (c) Alexander Batischev <eual.jp@gmail.com>
+//  * (c) Thomas Queiroz <thomasqueirozb@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) seekable seek'd tail'ing ringbuffer ringbuf
+
+#[macro_use]
+extern crate clap;
+
+#[macro_use]
+extern crate uucore;
+
+mod chunks;
+mod platform;
+use chunks::ReverseChunks;
+
+use clap::{App, Arg};
+use std::collections::VecDeque;
+use std::fmt;
+use std::fs::File;
+use std::io::{stdin, stdout, BufRead, BufReader, Read, Seek, SeekFrom, Write};
+use std::path::Path;
+use std::thread::sleep;
+use std::time::Duration;
+use uucore::parse_size::{parse_size, ParseSizeError};
+use uucore::ringbuffer::RingBuffer;
+
+#[cfg(unix)]
+use crate::platform::stdin_is_pipe_or_fifo;
+
+pub mod options {
+    pub mod verbosity {
+        pub static QUIET: &str = "quiet";
+        pub static VERBOSE: &str = "verbose";
+    }
+    pub static BYTES: &str = "bytes";
+    pub static FOLLOW: &str = "follow";
+    pub static LINES: &str = "lines";
+    pub static PID: &str = "pid";
+    pub static SLEEP_INT: &str = "sleep-interval";
+    pub static ZERO_TERM: &str = "zero-terminated";
+    pub static ARG_FILES: &str = "files";
+}
+
+enum FilterMode {
+    Bytes(usize),
+    Lines(usize, u8), // (number of lines, delimiter)
+}
+
+struct Settings {
+    mode: FilterMode,
+    sleep_msec: u32,
+    beginning: bool,
+    follow: bool,
+    pid: platform::Pid,
+}
+
+impl Default for Settings {
+    fn default() -> Settings {
+        Settings {
+            mode: FilterMode::Lines(10, b'\n'),
+            sleep_msec: 1000,
+            beginning: false,
+            follow: false,
+            pid: 0,
+        }
+    }
+}
+
+#[allow(clippy::cognitive_complexity)]
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let mut settings: Settings = Default::default();
+
+    let app = uu_app();
+
+    let matches = app.get_matches_from(args);
+
+    settings.follow = matches.is_present(options::FOLLOW);
+    if settings.follow {
+        if let Some(n) = matches.value_of(options::SLEEP_INT) {
+            let parsed: Option<u32> = n.parse().ok();
+            if let Some(m) = parsed {
+                settings.sleep_msec = m * 1000
+            }
+        }
+    }
+
+    if let Some(pid_str) = matches.value_of(options::PID) {
+        if let Ok(pid) = pid_str.parse() {
+            settings.pid = pid;
+            if pid != 0 {
+                if !settings.follow {
+                    show_warning!("PID ignored; --pid=PID is useful only when following");
+                }
+
+                if !platform::supports_pid_checks(pid) {
+                    show_warning!("--pid=PID is not supported on this system");
+                    settings.pid = 0;
+                }
+            }
+        }
+    }
+
+    let mode_and_beginning = if let Some(arg) = matches.value_of(options::BYTES) {
+        match parse_num(arg) {
+            Ok((n, beginning)) => (FilterMode::Bytes(n), beginning),
+            Err(e) => crash!(1, "invalid number of bytes: {}", e.to_string()),
+        }
+    } else if let Some(arg) = matches.value_of(options::LINES) {
+        match parse_num(arg) {
+            Ok((n, beginning)) => (FilterMode::Lines(n, b'\n'), beginning),
+            Err(e) => crash!(1, "invalid number of lines: {}", e.to_string()),
+        }
+    } else {
+        (FilterMode::Lines(10, b'\n'), false)
+    };
+    settings.mode = mode_and_beginning.0;
+    settings.beginning = mode_and_beginning.1;
+
+    if matches.is_present(options::ZERO_TERM) {
+        if let FilterMode::Lines(count, _) = settings.mode {
+            settings.mode = FilterMode::Lines(count, 0);
+        }
+    }
+
+    let verbose = matches.is_present(options::verbosity::VERBOSE);
+    let quiet = matches.is_present(options::verbosity::QUIET);
+
+    let files: Vec<String> = matches
+        .values_of(options::ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_else(|| vec![String::from("-")]);
+
+    let multiple = files.len() > 1;
+    let mut first_header = true;
+    let mut readers: Vec<(Box<dyn BufRead>, &String)> = Vec::new();
+
+    #[cfg(unix)]
+    let stdin_string = String::from("standard input");
+
+    for filename in &files {
+        let use_stdin = filename.as_str() == "-";
+        if (multiple || verbose) && !quiet {
+            if !first_header {
+                println!();
+            }
+            if use_stdin {
+                println!("==> standard input <==");
+            } else {
+                println!("==> {} <==", filename);
+            }
+        }
+        first_header = false;
+
+        if use_stdin {
+            let mut reader = BufReader::new(stdin());
+            unbounded_tail(&mut reader, &settings);
+
+            // Don't follow stdin since there are no checks for pipes/FIFOs
+            //
+            // FIXME windows has GetFileType which can determine if the file is a pipe/FIFO
+            // so this check can also be performed
+
+            #[cfg(unix)]
+            {
+                /*
+                POSIX specification regarding tail -f
+
+                If the input file is a regular file or if the file operand specifies a FIFO, do not
+                terminate after the last line of the input file has been copied, but read and copy
+                further bytes from the input file when they become available. If no file operand is
+                specified and standard input is a pipe or FIFO, the -f option shall be ignored. If
+                the input file is not a FIFO, pipe, or regular file, it is unspecified whether or
+                not the -f option shall be ignored.
+                */
+
+                if settings.follow && !stdin_is_pipe_or_fifo() {
+                    readers.push((Box::new(reader), &stdin_string));
+                }
+            }
+        } else {
+            let path = Path::new(filename);
+            if path.is_dir() {
+                continue;
+            }
+            let mut file = File::open(&path).unwrap();
+            if is_seekable(&mut file) {
+                bounded_tail(&mut file, &settings);
+                if settings.follow {
+                    let reader = BufReader::new(file);
+                    readers.push((Box::new(reader), filename));
+                }
+            } else {
+                let mut reader = BufReader::new(file);
+                unbounded_tail(&mut reader, &settings);
+                if settings.follow {
+                    readers.push((Box::new(reader), filename));
+                }
+            }
+        }
+    }
+
+    if settings.follow {
+        follow(&mut readers[..], &settings);
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about("output the last part of files")
+        // TODO: add usage
+        .arg(
+            Arg::with_name(options::BYTES)
+                .short("c")
+                .long(options::BYTES)
+                .takes_value(true)
+                .allow_hyphen_values(true)
+                .overrides_with_all(&[options::BYTES, options::LINES])
+                .help("Number of bytes to print"),
+        )
+        .arg(
+            Arg::with_name(options::FOLLOW)
+                .short("f")
+                .long(options::FOLLOW)
+                .help("Print the file as it grows"),
+        )
+        .arg(
+            Arg::with_name(options::LINES)
+                .short("n")
+                .long(options::LINES)
+                .takes_value(true)
+                .allow_hyphen_values(true)
+                .overrides_with_all(&[options::BYTES, options::LINES])
+                .help("Number of lines to print"),
+        )
+        .arg(
+            Arg::with_name(options::PID)
+                .long(options::PID)
+                .takes_value(true)
+                .help("with -f, terminate after process ID, PID dies"),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::QUIET)
+                .short("q")
+                .long(options::verbosity::QUIET)
+                .visible_alias("silent")
+                .overrides_with_all(&[options::verbosity::QUIET, options::verbosity::VERBOSE])
+                .help("never output headers giving file names"),
+        )
+        .arg(
+            Arg::with_name(options::SLEEP_INT)
+                .short("s")
+                .takes_value(true)
+                .long(options::SLEEP_INT)
+                .help("Number or seconds to sleep between polling the file when running with -f"),
+        )
+        .arg(
+            Arg::with_name(options::verbosity::VERBOSE)
+                .short("v")
+                .long(options::verbosity::VERBOSE)
+                .overrides_with_all(&[options::verbosity::QUIET, options::verbosity::VERBOSE])
+                .help("always output headers giving file names"),
+        )
+        .arg(
+            Arg::with_name(options::ZERO_TERM)
+                .short("z")
+                .long(options::ZERO_TERM)
+                .help("Line delimiter is NUL, not newline"),
+        )
+        .arg(
+            Arg::with_name(options::ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1),
+        )
+}
+
+fn follow<T: BufRead>(readers: &mut [(T, &String)], settings: &Settings) {
+    assert!(settings.follow);
+    if readers.is_empty() {
+        return;
+    }
+
+    let mut last = readers.len() - 1;
+    let mut read_some = false;
+    let mut process = platform::ProcessChecker::new(settings.pid);
+
+    loop {
+        sleep(Duration::new(0, settings.sleep_msec * 1000));
+
+        let pid_is_dead = !read_some && settings.pid != 0 && process.is_dead();
+        read_some = false;
+
+        for (i, (reader, filename)) in readers.iter_mut().enumerate() {
+            // Print all new content since the last pass
+            loop {
+                let mut datum = String::new();
+                match reader.read_line(&mut datum) {
+                    Ok(0) => break,
+                    Ok(_) => {
+                        read_some = true;
+                        if i != last {
+                            println!("\n==> {} <==", filename);
+                            last = i;
+                        }
+                        print!("{}", datum);
+                    }
+                    Err(err) => panic!("{}", err),
+                }
+            }
+        }
+
+        if pid_is_dead {
+            break;
+        }
+    }
+}
+
+/// Iterate over bytes in the file, in reverse, until we find the
+/// `num_delimiters` instance of `delimiter`. The `file` is left seek'd to the
+/// position just after that delimiter.
+fn backwards_thru_file(file: &mut File, num_delimiters: usize, delimiter: u8) {
+    // This variable counts the number of delimiters found in the file
+    // so far (reading from the end of the file toward the beginning).
+    let mut counter = 0;
+
+    for (block_idx, slice) in ReverseChunks::new(file).enumerate() {
+        // Iterate over each byte in the slice in reverse order.
+        let mut iter = slice.iter().enumerate().rev();
+
+        // Ignore a trailing newline in the last block, if there is one.
+        if block_idx == 0 {
+            if let Some(c) = slice.last() {
+                if *c == delimiter {
+                    iter.next();
+                }
+            }
+        }
+
+        // For each byte, increment the count of the number of
+        // delimiters found. If we have found more than the specified
+        // number of delimiters, terminate the search and seek to the
+        // appropriate location in the file.
+        for (i, ch) in iter {
+            if *ch == delimiter {
+                counter += 1;
+                if counter >= num_delimiters {
+                    // After each iteration of the outer loop, the
+                    // cursor in the file is at the *beginning* of the
+                    // block, so seeking forward by `i + 1` bytes puts
+                    // us right after the found delimiter.
+                    file.seek(SeekFrom::Current((i + 1) as i64)).unwrap();
+                    return;
+                }
+            }
+        }
+    }
+}
+
+/// When tail'ing a file, we do not need to read the whole file from start to
+/// finish just to find the last n lines or bytes. Instead, we can seek to the
+/// end of the file, and then read the file "backwards" in blocks of size
+/// `BLOCK_SIZE` until we find the location of the first line/byte. This ends up
+/// being a nice performance win for very large files.
+fn bounded_tail(file: &mut File, settings: &Settings) {
+    // Find the position in the file to start printing from.
+    match settings.mode {
+        FilterMode::Lines(count, delimiter) => {
+            backwards_thru_file(file, count as usize, delimiter);
+        }
+        FilterMode::Bytes(count) => {
+            file.seek(SeekFrom::End(-(count as i64))).unwrap();
+        }
+    }
+
+    // Print the target section of the file.
+    let stdout = stdout();
+    let mut stdout = stdout.lock();
+    std::io::copy(file, &mut stdout).unwrap();
+}
+
+/// Collect the last elements of an iterator into a `VecDeque`.
+///
+/// This function returns a [`VecDeque`] containing either the last
+/// `count` elements of `iter`, an [`Iterator`] over [`Result`]
+/// instances, or all but the first `count` elements of `iter`. If
+/// `beginning` is `true`, then all but the first `count` elements are
+/// returned.
+///
+/// # Panics
+///
+/// If any element of `iter` is an [`Err`], then this function panics.
+fn unbounded_tail_collect<T, E>(
+    iter: impl Iterator<Item = Result<T, E>>,
+    count: usize,
+    beginning: bool,
+) -> VecDeque<T>
+where
+    E: fmt::Debug,
+{
+    if beginning {
+        // GNU `tail` seems to index bytes and lines starting at 1, not
+        // at 0. It seems to treat `+0` and `+1` as the same thing.
+        let i = count.max(1) - 1;
+        iter.skip(i as usize).map(|r| r.unwrap()).collect()
+    } else {
+        RingBuffer::from_iter(iter.map(|r| r.unwrap()), count as usize).data
+    }
+}
+
+fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) {
+    // Read through each line/char and store them in a ringbuffer that always
+    // contains count lines/chars. When reaching the end of file, output the
+    // data in the ringbuf.
+    match settings.mode {
+        FilterMode::Lines(count, _) => {
+            for line in unbounded_tail_collect(reader.lines(), count, settings.beginning) {
+                println!("{}", line);
+            }
+        }
+        FilterMode::Bytes(count) => {
+            for byte in unbounded_tail_collect(reader.bytes(), count, settings.beginning) {
+                let mut stdout = stdout();
+                print_byte(&mut stdout, byte);
+            }
+        }
+    }
+}
+
+fn is_seekable<T: Seek>(file: &mut T) -> bool {
+    file.seek(SeekFrom::Current(0)).is_ok()
+}
+
+#[inline]
+fn print_byte<T: Write>(stdout: &mut T, ch: u8) {
+    if let Err(err) = stdout.write(&[ch]) {
+        crash!(1, "{}", err);
+    }
+}
+
+fn parse_num(src: &str) -> Result<(usize, bool), ParseSizeError> {
+    let mut size_string = src.trim();
+    let mut starting_with = false;
+
+    if let Some(c) = size_string.chars().next() {
+        if c == '+' || c == '-' {
+            // tail: '-' is not documented (8.32 man pages)
+            size_string = &size_string[1..];
+            if c == '+' {
+                starting_with = true;
+            }
+        }
+    } else {
+        return Err(ParseSizeError::ParseFailure(src.to_string()));
+    }
+
+    parse_size(size_string).map(|n| (n, starting_with))
+}
+
+
\ No newline at end of file diff --git a/src/uu_tee/tee.rs.html b/src/uu_tee/tee.rs.html new file mode 100644 index 000000000..f72496bb7 --- /dev/null +++ b/src/uu_tee/tee.rs.html @@ -0,0 +1,451 @@ +tee.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Aleksander Bielawski <pabzdzdzwiagief@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use retain_mut::RetainMut;
+use std::fs::OpenOptions;
+use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
+use std::path::{Path, PathBuf};
+
+#[cfg(unix)]
+use uucore::libc;
+
+static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";
+
+mod options {
+    pub const APPEND: &str = "append";
+    pub const IGNORE_INTERRUPTS: &str = "ignore-interrupts";
+    pub const FILE: &str = "file";
+}
+
+#[allow(dead_code)]
+struct Options {
+    append: bool,
+    ignore_interrupts: bool,
+    files: Vec<String>,
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let options = Options {
+        append: matches.is_present(options::APPEND),
+        ignore_interrupts: matches.is_present(options::IGNORE_INTERRUPTS),
+        files: matches
+            .values_of(options::FILE)
+            .map(|v| v.map(ToString::to_string).collect())
+            .unwrap_or_default(),
+    };
+
+    match tee(options) {
+        Ok(_) => 0,
+        Err(_) => 1,
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .after_help("If a FILE is -, it refers to a file named - .")
+        .arg(
+            Arg::with_name(options::APPEND)
+                .long(options::APPEND)
+                .short("a")
+                .help("append to the given FILEs, do not overwrite"),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_INTERRUPTS)
+                .long(options::IGNORE_INTERRUPTS)
+                .short("i")
+                .help("ignore interrupt signals (ignored on non-Unix platforms)"),
+        )
+        .arg(Arg::with_name(options::FILE).multiple(true))
+}
+
+#[cfg(unix)]
+fn ignore_interrupts() -> Result<()> {
+    let ret = unsafe { libc::signal(libc::SIGINT, libc::SIG_IGN) };
+    if ret == libc::SIG_ERR {
+        return Err(Error::new(ErrorKind::Other, ""));
+    }
+    Ok(())
+}
+
+#[cfg(not(unix))]
+fn ignore_interrupts() -> Result<()> {
+    // Do nothing.
+    Ok(())
+}
+
+fn tee(options: Options) -> Result<()> {
+    if options.ignore_interrupts {
+        ignore_interrupts()?
+    }
+    let mut writers: Vec<NamedWriter> = options
+        .files
+        .clone()
+        .into_iter()
+        .map(|file| NamedWriter {
+            name: file.clone(),
+            inner: open(file, options.append),
+        })
+        .collect();
+
+    writers.insert(
+        0,
+        NamedWriter {
+            name: "'standard output'".to_owned(),
+            inner: Box::new(stdout()),
+        },
+    );
+
+    let mut output = MultiWriter::new(writers);
+    let input = &mut NamedReader {
+        inner: Box::new(stdin()) as Box<dyn Read>,
+    };
+
+    // TODO: replaced generic 'copy' call to be able to stop copying
+    // if all outputs are closed (due to errors)
+    if copy(input, &mut output).is_err() || output.flush().is_err() || output.error_occurred() {
+        Err(Error::new(ErrorKind::Other, ""))
+    } else {
+        Ok(())
+    }
+}
+
+fn open(name: String, append: bool) -> Box<dyn Write> {
+    let path = PathBuf::from(name.clone());
+    let inner: Box<dyn Write> = {
+        let mut options = OpenOptions::new();
+        let mode = if append {
+            options.append(true)
+        } else {
+            options.truncate(true)
+        };
+        match mode.write(true).create(true).open(path.as_path()) {
+            Ok(file) => Box::new(file),
+            Err(_) => Box::new(sink()),
+        }
+    };
+    Box::new(NamedWriter { inner, name }) as Box<dyn Write>
+}
+
+struct MultiWriter {
+    writers: Vec<NamedWriter>,
+    initial_len: usize,
+}
+
+impl MultiWriter {
+    fn new(writers: Vec<NamedWriter>) -> Self {
+        Self {
+            initial_len: writers.len(),
+            writers,
+        }
+    }
+    fn error_occurred(&self) -> bool {
+        self.writers.len() != self.initial_len
+    }
+}
+
+impl Write for MultiWriter {
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        self.writers.retain_mut(|writer| {
+            let result = writer.write_all(buf);
+            match result {
+                Err(f) => {
+                    show_error!("{}: {}", writer.name, f.to_string());
+                    false
+                }
+                _ => true,
+            }
+        });
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> Result<()> {
+        self.writers.retain_mut(|writer| {
+            let result = writer.flush();
+            match result {
+                Err(f) => {
+                    show_error!("{}: {}", writer.name, f.to_string());
+                    false
+                }
+                _ => true,
+            }
+        });
+        Ok(())
+    }
+}
+
+struct NamedWriter {
+    inner: Box<dyn Write>,
+    pub name: String,
+}
+
+impl Write for NamedWriter {
+    fn write(&mut self, buf: &[u8]) -> Result<usize> {
+        self.inner.write(buf)
+    }
+
+    fn flush(&mut self) -> Result<()> {
+        self.inner.flush()
+    }
+}
+
+struct NamedReader {
+    inner: Box<dyn Read>,
+}
+
+impl Read for NamedReader {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        match self.inner.read(buf) {
+            Err(f) => {
+                show_error!("{}: {}", Path::new("stdin").display(), f.to_string());
+                Err(f)
+            }
+            okay => okay,
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_test/parser.rs.html b/src/uu_test/parser.rs.html new file mode 100644 index 000000000..d1b75ecc8 --- /dev/null +++ b/src/uu_test/parser.rs.html @@ -0,0 +1,663 @@ +parser.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Daniel Rocco <drocco@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (grammar) BOOLOP STRLEN FILETEST FILEOP INTOP STRINGOP ; (vars) LParen StrlenOp
+
+use std::ffi::OsString;
+use std::iter::Peekable;
+
+/// Represents a parsed token from a test expression
+#[derive(Debug, PartialEq)]
+pub enum Symbol {
+    LParen,
+    Bang,
+    BoolOp(OsString),
+    Literal(OsString),
+    StringOp(OsString),
+    IntOp(OsString),
+    FileOp(OsString),
+    StrlenOp(OsString),
+    FiletestOp(OsString),
+    None,
+}
+
+impl Symbol {
+    /// Create a new Symbol from an OsString.
+    ///
+    /// Returns Symbol::None in place of None
+    fn new(token: Option<OsString>) -> Symbol {
+        match token {
+            Some(s) => match s.to_string_lossy().as_ref() {
+                "(" => Symbol::LParen,
+                "!" => Symbol::Bang,
+                "-a" | "-o" => Symbol::BoolOp(s),
+                "=" | "==" | "!=" => Symbol::StringOp(s),
+                "-eq" | "-ge" | "-gt" | "-le" | "-lt" | "-ne" => Symbol::IntOp(s),
+                "-ef" | "-nt" | "-ot" => Symbol::FileOp(s),
+                "-n" | "-z" => Symbol::StrlenOp(s),
+                "-b" | "-c" | "-d" | "-e" | "-f" | "-g" | "-G" | "-h" | "-k" | "-L" | "-O"
+                | "-p" | "-r" | "-s" | "-S" | "-t" | "-u" | "-w" | "-x" => Symbol::FiletestOp(s),
+                _ => Symbol::Literal(s),
+            },
+            None => Symbol::None,
+        }
+    }
+
+    /// Convert this Symbol into a Symbol::Literal, useful for cases where
+    /// test treats an operator as a string operand (test has no reserved
+    /// words).
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self` is Symbol::None
+    fn into_literal(self) -> Symbol {
+        Symbol::Literal(match self {
+            Symbol::LParen => OsString::from("("),
+            Symbol::Bang => OsString::from("!"),
+            Symbol::BoolOp(s)
+            | Symbol::Literal(s)
+            | Symbol::StringOp(s)
+            | Symbol::IntOp(s)
+            | Symbol::FileOp(s)
+            | Symbol::StrlenOp(s)
+            | Symbol::FiletestOp(s) => s,
+            Symbol::None => panic!(),
+        })
+    }
+}
+
+/// Recursive descent parser for test, which converts a list of OsStrings
+/// (typically command line arguments) into a stack of Symbols in postfix
+/// order.
+///
+/// Grammar:
+///
+///   EXPR → TERM | EXPR BOOLOP EXPR
+///   TERM → ( EXPR )
+///   TERM → ( )
+///   TERM → ! EXPR
+///   TERM → UOP str
+///   UOP → STRLEN | FILETEST
+///   TERM → str OP str
+///   TERM → str | 𝜖
+///   OP → STRINGOP | INTOP | FILEOP
+///   STRINGOP → = | == | !=
+///   INTOP → -eq | -ge | -gt | -le | -lt | -ne
+///   FILEOP → -ef | -nt | -ot
+///   STRLEN → -n | -z
+///   FILETEST → -b | -c | -d | -e | -f | -g | -G | -h | -k | -L | -O | -p |
+///               -r | -s | -S | -t | -u | -w | -x
+///   BOOLOP → -a | -o
+///
+#[derive(Debug)]
+struct Parser {
+    tokens: Peekable<std::vec::IntoIter<OsString>>,
+    pub stack: Vec<Symbol>,
+}
+
+impl Parser {
+    /// Construct a new Parser from a `Vec<OsString>` of tokens.
+    fn new(tokens: Vec<OsString>) -> Parser {
+        Parser {
+            tokens: tokens.into_iter().peekable(),
+            stack: vec![],
+        }
+    }
+
+    /// Fetch the next token from the input stream as a Symbol.
+    fn next_token(&mut self) -> Symbol {
+        Symbol::new(self.tokens.next())
+    }
+
+    /// Peek at the next token from the input stream, returning it as a Symbol.
+    /// The stream is unchanged and will return the same Symbol on subsequent
+    /// calls to `next()` or `peek()`.
+    fn peek(&mut self) -> Symbol {
+        Symbol::new(self.tokens.peek().map(|s| s.to_os_string()))
+    }
+
+    /// Test if the next token in the stream is a BOOLOP (-a or -o), without
+    /// removing the token from the stream.
+    fn peek_is_boolop(&mut self) -> bool {
+        matches!(self.peek(), Symbol::BoolOp(_))
+    }
+
+    /// Parse an expression.
+    ///
+    ///   EXPR → TERM | EXPR BOOLOP EXPR
+    fn expr(&mut self) {
+        if !self.peek_is_boolop() {
+            self.term();
+        }
+        self.maybe_boolop();
+    }
+
+    /// Parse a term token and possible subsequent symbols: "(", "!", UOP,
+    /// literal, or None.
+    fn term(&mut self) {
+        let symbol = self.next_token();
+
+        match symbol {
+            Symbol::LParen => self.lparen(),
+            Symbol::Bang => self.bang(),
+            Symbol::StrlenOp(_) => self.uop(symbol),
+            Symbol::FiletestOp(_) => self.uop(symbol),
+            Symbol::None => self.stack.push(symbol),
+            literal => self.literal(literal),
+        }
+    }
+
+    /// Parse a (possibly) parenthesized expression.
+    ///
+    /// test has no reserved keywords, so "(" will be interpreted as a literal
+    /// if it is followed by nothing or a comparison operator OP.
+    fn lparen(&mut self) {
+        match self.peek() {
+            // lparen is a literal when followed by nothing or comparison
+            Symbol::None | Symbol::StringOp(_) | Symbol::IntOp(_) | Symbol::FileOp(_) => {
+                self.literal(Symbol::LParen.into_literal());
+            }
+            // empty parenthetical
+            Symbol::Literal(s) if s == ")" => {}
+            _ => {
+                self.expr();
+                match self.next_token() {
+                    Symbol::Literal(s) if s == ")" => (),
+                    _ => panic!("expected ')'"),
+                }
+            }
+        }
+    }
+
+    /// Parse a (possibly) negated expression.
+    ///
+    /// Example cases:
+    ///
+    /// * `! =`: negate the result of the implicit string length test of `=`
+    /// * `! = foo`: compare the literal strings `!` and `foo`
+    /// * `! = = str`: negate comparison of literal `=` and `str`
+    /// * `!`: bang followed by nothing is literal
+    /// * `! EXPR`: negate the result of the expression
+    ///
+    /// Combined Boolean & negation:
+    ///
+    /// * `! ( EXPR ) [BOOLOP EXPR]`: negate the parenthesized expression only
+    /// * `! UOP str BOOLOP EXPR`: negate the unary subexpression
+    /// * `! str BOOLOP str`: negate the entire Boolean expression
+    /// * `! str BOOLOP EXPR BOOLOP EXPR`: negate the value of the first `str` term
+    ///
+    fn bang(&mut self) {
+        match self.peek() {
+            Symbol::StringOp(_) | Symbol::IntOp(_) | Symbol::FileOp(_) | Symbol::BoolOp(_) => {
+                // we need to peek ahead one more token to disambiguate the first
+                // three cases listed above
+                let peek2 = Symbol::new(self.tokens.clone().nth(1));
+
+                match peek2 {
+                    // case 1: `! <OP as literal>`
+                    // case 3: `! = OP str`
+                    Symbol::StringOp(_) | Symbol::None => {
+                        // op is literal
+                        let op = self.next_token().into_literal();
+                        self.literal(op);
+                        self.stack.push(Symbol::Bang);
+                    }
+                    // case 2: `<! as literal> OP str [BOOLOP EXPR]`.
+                    _ => {
+                        // bang is literal; parsing continues with op
+                        self.literal(Symbol::Bang.into_literal());
+                        self.maybe_boolop();
+                    }
+                }
+            }
+
+            // bang followed by nothing is literal
+            Symbol::None => self.stack.push(Symbol::Bang.into_literal()),
+
+            _ => {
+                // peek ahead up to 4 tokens to determine if we need to negate
+                // the entire expression or just the first term
+                let peek4: Vec<Symbol> = self
+                    .tokens
+                    .clone()
+                    .take(4)
+                    .map(|token| Symbol::new(Some(token)))
+                    .collect();
+
+                match peek4.as_slice() {
+                    // we peeked ahead 4 but there were only 3 tokens left
+                    [Symbol::Literal(_), Symbol::BoolOp(_), Symbol::Literal(_)] => {
+                        self.expr();
+                        self.stack.push(Symbol::Bang);
+                    }
+                    _ => {
+                        self.term();
+                        self.stack.push(Symbol::Bang);
+                    }
+                }
+            }
+        }
+    }
+
+    /// Peek at the next token and parse it as a BOOLOP or string literal,
+    /// as appropriate.
+    fn maybe_boolop(&mut self) {
+        if self.peek_is_boolop() {
+            let symbol = self.next_token();
+
+            // BoolOp by itself interpreted as Literal
+            if let Symbol::None = self.peek() {
+                self.literal(symbol.into_literal());
+            } else {
+                self.boolop(symbol);
+                self.maybe_boolop();
+            }
+        }
+    }
+
+    /// Parse a Boolean expression.
+    ///
+    /// Logical and (-a) has higher precedence than or (-o), so in an
+    /// expression like `foo -o '' -a ''`, the and subexpression is evaluated
+    /// first.
+    fn boolop(&mut self, op: Symbol) {
+        if op == Symbol::BoolOp(OsString::from("-a")) {
+            self.term();
+        } else {
+            self.expr();
+        }
+        self.stack.push(op);
+    }
+
+    /// Parse a (possible) unary argument test (string length or file
+    /// attribute check).
+    ///
+    /// If a UOP is followed by nothing it is interpreted as a literal string.
+    fn uop(&mut self, op: Symbol) {
+        match self.next_token() {
+            Symbol::None => self.stack.push(op.into_literal()),
+            symbol => {
+                self.stack.push(symbol.into_literal());
+                self.stack.push(op);
+            }
+        }
+    }
+
+    /// Parse a string literal, optionally followed by a comparison operator
+    /// and a second string literal.
+    fn literal(&mut self, token: Symbol) {
+        self.stack.push(token.into_literal());
+
+        // EXPR → str OP str
+        match self.peek() {
+            Symbol::StringOp(_) | Symbol::IntOp(_) | Symbol::FileOp(_) => {
+                let op = self.next_token();
+
+                match self.next_token() {
+                    Symbol::None => panic!("missing argument after {:?}", op),
+                    token => self.stack.push(token.into_literal()),
+                }
+
+                self.stack.push(op);
+            }
+            _ => {}
+        }
+    }
+
+    /// Parser entry point: parse the token stream `self.tokens`, storing the
+    /// resulting `Symbol` stack in `self.stack`.
+    fn parse(&mut self) -> Result<(), String> {
+        self.expr();
+
+        match self.tokens.next() {
+            Some(token) => Err(format!("extra argument '{}'", token.to_string_lossy())),
+            None => Ok(()),
+        }
+    }
+}
+
+/// Parse the token stream `args`, returning a `Symbol` stack representing the
+/// operations to perform in postfix order.
+pub fn parse(args: Vec<OsString>) -> Result<Vec<Symbol>, String> {
+    let mut p = Parser::new(args);
+    p.parse()?;
+    Ok(p.stack)
+}
+
+
\ No newline at end of file diff --git a/src/uu_test/test.rs.html b/src/uu_test/test.rs.html new file mode 100644 index 000000000..b0d06f3f8 --- /dev/null +++ b/src/uu_test/test.rs.html @@ -0,0 +1,799 @@ +test.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+
+// This file is part of the uutils coreutils package.
+//
+// (c) mahkoh (ju.orth [at] gmail [dot] com)
+// (c) Daniel Rocco <drocco@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (vars) egid euid FiletestOp StrlenOp
+
+mod parser;
+
+use clap::{crate_version, App, AppSettings};
+use parser::{parse, Symbol};
+use std::ffi::{OsStr, OsString};
+use std::path::Path;
+
+const USAGE: &str = "test EXPRESSION
+or:  test
+or:  [ EXPRESSION ]
+or:  [ ]
+or:  [ OPTION";
+
+// We use after_help so that this comes after the usage string (it would come before if we used about)
+const AFTER_HELP: &str = "
+Exit with the status determined by EXPRESSION.
+
+An omitted EXPRESSION defaults to false.  Otherwise,
+EXPRESSION is true or false and sets exit status.  It is one of:
+
+  ( EXPRESSION )               EXPRESSION is true
+  ! EXPRESSION                 EXPRESSION is false
+  EXPRESSION1 -a EXPRESSION2   both EXPRESSION1 and EXPRESSION2 are true
+  EXPRESSION1 -o EXPRESSION2   either EXPRESSION1 or EXPRESSION2 is true
+
+  -n STRING            the length of STRING is nonzero
+  STRING               equivalent to -n STRING
+  -z STRING            the length of STRING is zero
+  STRING1 = STRING2    the strings are equal
+  STRING1 != STRING2   the strings are not equal
+
+  INTEGER1 -eq INTEGER2   INTEGER1 is equal to INTEGER2
+  INTEGER1 -ge INTEGER2   INTEGER1 is greater than or equal to INTEGER2
+  INTEGER1 -gt INTEGER2   INTEGER1 is greater than INTEGER2
+  INTEGER1 -le INTEGER2   INTEGER1 is less than or equal to INTEGER2
+  INTEGER1 -lt INTEGER2   INTEGER1 is less than INTEGER2
+  INTEGER1 -ne INTEGER2   INTEGER1 is not equal to INTEGER2
+
+  FILE1 -ef FILE2   FILE1 and FILE2 have the same device and inode numbers
+  FILE1 -nt FILE2   FILE1 is newer (modification date) than FILE2
+  FILE1 -ot FILE2   FILE1 is older than FILE2
+
+  -b FILE     FILE exists and is block special
+  -c FILE     FILE exists and is character special
+  -d FILE     FILE exists and is a directory
+  -e FILE     FILE exists
+  -f FILE     FILE exists and is a regular file
+  -g FILE     FILE exists and is set-group-ID
+  -G FILE     FILE exists and is owned by the effective group ID
+  -h FILE     FILE exists and is a symbolic link (same as -L)
+  -k FILE     FILE exists and has its sticky bit set
+  -L FILE     FILE exists and is a symbolic link (same as -h)
+  -N FILE     FILE exists and has been modified since it was last read
+  -O FILE     FILE exists and is owned by the effective user ID
+  -p FILE     FILE exists and is a named pipe
+  -r FILE     FILE exists and read permission is granted
+  -s FILE     FILE exists and has a size greater than zero
+  -S FILE     FILE exists and is a socket
+  -t FD       file descriptor FD is opened on a terminal
+  -u FILE     FILE exists and its set-user-ID bit is set
+  -w FILE     FILE exists and write permission is granted
+  -x FILE     FILE exists and execute (or search) permission is granted
+
+Except for -h and -L, all FILE-related tests dereference symbolic links.
+Beware that parentheses need to be escaped (e.g., by backslashes) for shells.
+INTEGER may also be -l STRING, which evaluates to the length of STRING.
+
+NOTE: Binary -a and -o are inherently ambiguous.  Use 'test EXPR1 && test
+EXPR2' or 'test EXPR1 || test EXPR2' instead.
+
+NOTE: [ honors the --help and --version options, but test does not.
+test treats each of those as it treats any other nonempty STRING.
+
+NOTE: your shell may have its own version of test and/or [, which usually supersedes
+the version described here.  Please refer to your shell's documentation
+for details about the options it supports.";
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .setting(AppSettings::DisableHelpFlags)
+        .setting(AppSettings::DisableVersion)
+}
+
+pub fn uumain(mut args: impl uucore::Args) -> i32 {
+    let program = args.next().unwrap_or_else(|| OsString::from("test"));
+    let binary_name = Path::new(&program)
+        .file_name()
+        .unwrap_or_else(|| OsStr::new("test"))
+        .to_string_lossy();
+    let mut args: Vec<_> = args.collect();
+
+    if binary_name.ends_with('[') {
+        // If invoked as [ we should recognize --help and --version (but not -h or -v)
+        if args.len() == 1 && (args[0] == "--help" || args[0] == "--version") {
+            // Let clap pretty-print help and version
+            App::new(binary_name)
+                .version(crate_version!())
+                .usage(USAGE)
+                .after_help(AFTER_HELP)
+                // Disable printing of -h and -v as valid alternatives for --help and --version,
+                // since we don't recognize -h and -v as help/version flags.
+                .setting(AppSettings::NeedsLongHelp)
+                .setting(AppSettings::NeedsLongVersion)
+                .get_matches_from(std::iter::once(program).chain(args.into_iter()));
+            return 0;
+        }
+        // If invoked via name '[', matching ']' must be in the last arg
+        let last = args.pop();
+        if last != Some(OsString::from("]")) {
+            eprintln!("[: missing ']'");
+            return 2;
+        }
+    }
+
+    let result = parse(args).and_then(|mut stack| eval(&mut stack));
+
+    match result {
+        Ok(result) => {
+            if result {
+                0
+            } else {
+                1
+            }
+        }
+        Err(e) => {
+            eprintln!("test: {}", e);
+            2
+        }
+    }
+}
+
+/// Evaluate a stack of Symbols, returning the result of the evaluation or
+/// an error message if evaluation failed.
+fn eval(stack: &mut Vec<Symbol>) -> Result<bool, String> {
+    macro_rules! pop_literal {
+        () => {
+            match stack.pop() {
+                Some(Symbol::Literal(s)) => s,
+                _ => panic!(),
+            }
+        };
+    }
+
+    let s = stack.pop();
+
+    match s {
+        Some(Symbol::Bang) => {
+            let result = eval(stack)?;
+
+            Ok(!result)
+        }
+        Some(Symbol::StringOp(op)) => {
+            let b = stack.pop();
+            let a = stack.pop();
+            Ok(if op == "!=" { a != b } else { a == b })
+        }
+        Some(Symbol::IntOp(op)) => {
+            let b = pop_literal!();
+            let a = pop_literal!();
+
+            Ok(integers(&a, &b, &op)?)
+        }
+        Some(Symbol::FileOp(_op)) => unimplemented!(),
+        Some(Symbol::StrlenOp(op)) => {
+            let s = match stack.pop() {
+                Some(Symbol::Literal(s)) => s,
+                Some(Symbol::None) => OsString::from(""),
+                None => {
+                    return Ok(true);
+                }
+                _ => {
+                    return Err(format!("missing argument after '{:?}'", op));
+                }
+            };
+
+            Ok(if op == "-z" {
+                s.is_empty()
+            } else {
+                !s.is_empty()
+            })
+        }
+        Some(Symbol::FiletestOp(op)) => {
+            let op = op.to_string_lossy();
+
+            let f = pop_literal!();
+
+            Ok(match op.as_ref() {
+                "-b" => path(&f, PathCondition::BlockSpecial),
+                "-c" => path(&f, PathCondition::CharacterSpecial),
+                "-d" => path(&f, PathCondition::Directory),
+                "-e" => path(&f, PathCondition::Exists),
+                "-f" => path(&f, PathCondition::Regular),
+                "-g" => path(&f, PathCondition::GroupIdFlag),
+                "-G" => path(&f, PathCondition::GroupOwns),
+                "-h" => path(&f, PathCondition::SymLink),
+                "-k" => path(&f, PathCondition::Sticky),
+                "-L" => path(&f, PathCondition::SymLink),
+                "-O" => path(&f, PathCondition::UserOwns),
+                "-p" => path(&f, PathCondition::Fifo),
+                "-r" => path(&f, PathCondition::Readable),
+                "-S" => path(&f, PathCondition::Socket),
+                "-s" => path(&f, PathCondition::NonEmpty),
+                "-t" => isatty(&f)?,
+                "-u" => path(&f, PathCondition::UserIdFlag),
+                "-w" => path(&f, PathCondition::Writable),
+                "-x" => path(&f, PathCondition::Executable),
+                _ => panic!(),
+            })
+        }
+        Some(Symbol::Literal(s)) => Ok(!s.is_empty()),
+        Some(Symbol::None) => Ok(false),
+        Some(Symbol::BoolOp(op)) => {
+            let b = eval(stack)?;
+            let a = eval(stack)?;
+
+            Ok(if op == "-a" { a && b } else { a || b })
+        }
+        None => Ok(false),
+        _ => Err("expected value".to_string()),
+    }
+}
+
+fn integers(a: &OsStr, b: &OsStr, op: &OsStr) -> Result<bool, String> {
+    let format_err = |value| format!("invalid integer '{}'", value);
+
+    let a = a.to_string_lossy();
+    let a: i64 = a.parse().map_err(|_| format_err(a))?;
+
+    let b = b.to_string_lossy();
+    let b: i64 = b.parse().map_err(|_| format_err(b))?;
+
+    let operator = op.to_string_lossy();
+    Ok(match operator.as_ref() {
+        "-eq" => a == b,
+        "-ne" => a != b,
+        "-gt" => a > b,
+        "-ge" => a >= b,
+        "-lt" => a < b,
+        "-le" => a <= b,
+        _ => return Err(format!("unknown operator '{}'", operator)),
+    })
+}
+
+fn isatty(fd: &OsStr) -> Result<bool, String> {
+    let fd = fd.to_string_lossy();
+
+    fd.parse()
+        .map_err(|_| format!("invalid integer '{}'", fd))
+        .map(|i| {
+            #[cfg(not(target_os = "redox"))]
+            unsafe {
+                libc::isatty(i) == 1
+            }
+            #[cfg(target_os = "redox")]
+            syscall::dup(i, b"termios").map(syscall::close).is_ok()
+        })
+}
+
+#[derive(Eq, PartialEq)]
+enum PathCondition {
+    BlockSpecial,
+    CharacterSpecial,
+    Directory,
+    Exists,
+    Regular,
+    GroupIdFlag,
+    GroupOwns,
+    SymLink,
+    Sticky,
+    UserOwns,
+    Fifo,
+    Readable,
+    Socket,
+    NonEmpty,
+    UserIdFlag,
+    Writable,
+    Executable,
+}
+
+#[cfg(not(windows))]
+fn path(path: &OsStr, condition: PathCondition) -> bool {
+    use std::fs::{self, Metadata};
+    use std::os::unix::fs::{FileTypeExt, MetadataExt};
+
+    const S_ISUID: u32 = 0o4000;
+    const S_ISGID: u32 = 0o2000;
+    const S_ISVTX: u32 = 0o1000;
+
+    enum Permission {
+        Read = 0o4,
+        Write = 0o2,
+        Execute = 0o1,
+    }
+
+    let geteuid = || {
+        #[cfg(not(target_os = "redox"))]
+        let euid = unsafe { libc::geteuid() };
+        #[cfg(target_os = "redox")]
+        let euid = syscall::geteuid().unwrap() as u32;
+
+        euid
+    };
+
+    let getegid = || {
+        #[cfg(not(target_os = "redox"))]
+        let egid = unsafe { libc::getegid() };
+        #[cfg(target_os = "redox")]
+        let egid = syscall::getegid().unwrap() as u32;
+
+        egid
+    };
+
+    let perm = |metadata: Metadata, p: Permission| {
+        if geteuid() == metadata.uid() {
+            metadata.mode() & ((p as u32) << 6) != 0
+        } else if getegid() == metadata.gid() {
+            metadata.mode() & ((p as u32) << 3) != 0
+        } else {
+            metadata.mode() & (p as u32) != 0
+        }
+    };
+
+    let metadata = if condition == PathCondition::SymLink {
+        fs::symlink_metadata(path)
+    } else {
+        fs::metadata(path)
+    };
+
+    let metadata = match metadata {
+        Ok(metadata) => metadata,
+        Err(_) => {
+            return false;
+        }
+    };
+
+    let file_type = metadata.file_type();
+
+    match condition {
+        PathCondition::BlockSpecial => file_type.is_block_device(),
+        PathCondition::CharacterSpecial => file_type.is_char_device(),
+        PathCondition::Directory => file_type.is_dir(),
+        PathCondition::Exists => true,
+        PathCondition::Regular => file_type.is_file(),
+        PathCondition::GroupIdFlag => metadata.mode() & S_ISGID != 0,
+        PathCondition::GroupOwns => metadata.gid() == getegid(),
+        PathCondition::SymLink => metadata.file_type().is_symlink(),
+        PathCondition::Sticky => metadata.mode() & S_ISVTX != 0,
+        PathCondition::UserOwns => metadata.uid() == geteuid(),
+        PathCondition::Fifo => file_type.is_fifo(),
+        PathCondition::Readable => perm(metadata, Permission::Read),
+        PathCondition::Socket => file_type.is_socket(),
+        PathCondition::NonEmpty => metadata.size() > 0,
+        PathCondition::UserIdFlag => metadata.mode() & S_ISUID != 0,
+        PathCondition::Writable => perm(metadata, Permission::Write),
+        PathCondition::Executable => perm(metadata, Permission::Execute),
+    }
+}
+
+#[cfg(windows)]
+fn path(path: &OsStr, condition: PathCondition) -> bool {
+    use std::fs::metadata;
+
+    let stat = match metadata(path) {
+        Ok(s) => s,
+        _ => return false,
+    };
+
+    match condition {
+        PathCondition::BlockSpecial => false,
+        PathCondition::CharacterSpecial => false,
+        PathCondition::Directory => stat.is_dir(),
+        PathCondition::Exists => true,
+        PathCondition::Regular => stat.is_file(),
+        PathCondition::GroupIdFlag => false,
+        PathCondition::GroupOwns => unimplemented!(),
+        PathCondition::SymLink => false,
+        PathCondition::Sticky => false,
+        PathCondition::UserOwns => unimplemented!(),
+        PathCondition::Fifo => false,
+        PathCondition::Readable => false, // TODO
+        PathCondition::Socket => false,
+        PathCondition::NonEmpty => stat.len() > 0,
+        PathCondition::UserIdFlag => false,
+        PathCondition::Writable => false,   // TODO
+        PathCondition::Executable => false, // TODO
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_timeout/timeout.rs.html b/src/uu_timeout/timeout.rs.html new file mode 100644 index 000000000..08ff07ade --- /dev/null +++ b/src/uu_timeout/timeout.rs.html @@ -0,0 +1,521 @@ +timeout.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) tstr sigstr cmdname setpgid sigchld
+
+#[macro_use]
+extern crate uucore;
+
+extern crate clap;
+
+use clap::{crate_version, App, AppSettings, Arg};
+use std::io::ErrorKind;
+use std::process::{Command, Stdio};
+use std::time::Duration;
+use uucore::process::ChildExt;
+use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION] DURATION COMMAND...",
+        uucore::execution_phrase()
+    )
+}
+
+const ERR_EXIT_STATUS: i32 = 125;
+
+pub mod options {
+    pub static FOREGROUND: &str = "foreground";
+    pub static KILL_AFTER: &str = "kill-after";
+    pub static SIGNAL: &str = "signal";
+    pub static PRESERVE_STATUS: &str = "preserve-status";
+    pub static VERBOSE: &str = "verbose";
+
+    // Positional args.
+    pub static DURATION: &str = "duration";
+    pub static COMMAND: &str = "command";
+}
+
+struct Config {
+    foreground: bool,
+    kill_after: Option<Duration>,
+    signal: usize,
+    duration: Duration,
+    preserve_status: bool,
+    verbose: bool,
+
+    command: Vec<String>,
+}
+
+impl Config {
+    fn from(options: clap::ArgMatches) -> Config {
+        let signal = match options.value_of(options::SIGNAL) {
+            Some(signal_) => {
+                let signal_result = signal_by_name_or_value(signal_);
+                match signal_result {
+                    None => {
+                        unreachable!("invalid signal '{}'", signal_);
+                    }
+                    Some(signal_value) => signal_value,
+                }
+            }
+            _ => uucore::signals::signal_by_name_or_value("TERM").unwrap(),
+        };
+
+        let kill_after = options
+            .value_of(options::KILL_AFTER)
+            .map(|time| uucore::parse_time::from_str(time).unwrap());
+
+        let duration: Duration =
+            uucore::parse_time::from_str(options.value_of(options::DURATION).unwrap()).unwrap();
+
+        let preserve_status: bool = options.is_present(options::PRESERVE_STATUS);
+        let foreground = options.is_present(options::FOREGROUND);
+        let verbose = options.is_present(options::VERBOSE);
+
+        let command = options
+            .values_of(options::COMMAND)
+            .unwrap()
+            .map(String::from)
+            .collect::<Vec<_>>();
+
+        Config {
+            foreground,
+            kill_after,
+            signal,
+            duration,
+            preserve_status,
+            verbose,
+            command,
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let usage = usage();
+
+    let app = uu_app().usage(&usage[..]);
+
+    let matches = app.get_matches_from(args);
+
+    let config = Config::from(matches);
+    timeout(
+        &config.command,
+        config.duration,
+        config.signal,
+        config.kill_after,
+        config.foreground,
+        config.preserve_status,
+        config.verbose,
+    )
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new("timeout")
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::FOREGROUND)
+                .long(options::FOREGROUND)
+                .help("when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out")
+        )
+        .arg(
+            Arg::with_name(options::KILL_AFTER)
+                .short("k")
+                .takes_value(true))
+        .arg(
+            Arg::with_name(options::PRESERVE_STATUS)
+                .long(options::PRESERVE_STATUS)
+                .help("exit with the same status as COMMAND, even when the command times out")
+        )
+        .arg(
+            Arg::with_name(options::SIGNAL)
+                .short("s")
+                .long(options::SIGNAL)
+                .help("specify the signal to be sent on timeout; SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals")
+                .takes_value(true)
+        )
+        .arg(
+            Arg::with_name(options::VERBOSE)
+              .short("v")
+              .long(options::VERBOSE)
+              .help("diagnose to stderr any signal sent upon timeout")
+        )
+        .arg(
+            Arg::with_name(options::DURATION)
+                .index(1)
+                .required(true)
+        )
+        .arg(
+            Arg::with_name(options::COMMAND)
+                .index(2)
+                .required(true)
+                .multiple(true)
+        )
+        .setting(AppSettings::TrailingVarArg)
+}
+
+/// Remove pre-existing SIGCHLD handlers that would make waiting for the child's exit code fail.
+fn unblock_sigchld() {
+    unsafe {
+        nix::sys::signal::signal(
+            nix::sys::signal::Signal::SIGCHLD,
+            nix::sys::signal::SigHandler::SigDfl,
+        )
+        .unwrap();
+    }
+}
+
+/// TODO: Improve exit codes, and make them consistent with the GNU Coreutils exit codes.
+
+fn timeout(
+    cmd: &[String],
+    duration: Duration,
+    signal: usize,
+    kill_after: Option<Duration>,
+    foreground: bool,
+    preserve_status: bool,
+    verbose: bool,
+) -> i32 {
+    if !foreground {
+        unsafe { libc::setpgid(0, 0) };
+    }
+    let mut process = match Command::new(&cmd[0])
+        .args(&cmd[1..])
+        .stdin(Stdio::inherit())
+        .stdout(Stdio::inherit())
+        .stderr(Stdio::inherit())
+        .spawn()
+    {
+        Ok(p) => p,
+        Err(err) => {
+            show_error!("failed to execute process: {}", err);
+            if err.kind() == ErrorKind::NotFound {
+                // FIXME: not sure which to use
+                return 127;
+            } else {
+                // FIXME: this may not be 100% correct...
+                return 126;
+            }
+        }
+    };
+    unblock_sigchld();
+    match process.wait_or_timeout(duration) {
+        Ok(Some(status)) => status.code().unwrap_or_else(|| status.signal().unwrap()),
+        Ok(None) => {
+            if verbose {
+                show_error!(
+                    "sending signal {} to command '{}'",
+                    signal_name_by_value(signal).unwrap(),
+                    cmd[0]
+                );
+            }
+            return_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
+            if let Some(kill_after) = kill_after {
+                match process.wait_or_timeout(kill_after) {
+                    Ok(Some(status)) => {
+                        if preserve_status {
+                            status.code().unwrap_or_else(|| status.signal().unwrap())
+                        } else {
+                            124
+                        }
+                    }
+                    Ok(None) => {
+                        if verbose {
+                            show_error!("sending signal KILL to command '{}'", cmd[0]);
+                        }
+                        return_if_err!(
+                            ERR_EXIT_STATUS,
+                            process.send_signal(
+                                uucore::signals::signal_by_name_or_value("KILL").unwrap()
+                            )
+                        );
+                        return_if_err!(ERR_EXIT_STATUS, process.wait());
+                        137
+                    }
+                    Err(_) => 124,
+                }
+            } else {
+                124
+            }
+        }
+        Err(_) => {
+            return_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
+            ERR_EXIT_STATUS
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_touch/touch.rs.html b/src/uu_touch/touch.rs.html new file mode 100644 index 000000000..62233bb82 --- /dev/null +++ b/src/uu_touch/touch.rs.html @@ -0,0 +1,557 @@ +touch.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Nick Platt <platt.nicholas@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) filetime strptime utcoff strs datetime MMDDhhmm
+
+pub extern crate filetime;
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg, ArgGroup};
+use filetime::*;
+use std::fs::{self, File};
+use std::path::Path;
+use uucore::error::{FromIo, UError, UResult, USimpleError};
+
+static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
+pub mod options {
+    // Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
+    pub static SOURCES: &str = "sources";
+    pub mod sources {
+        pub static DATE: &str = "date";
+        pub static REFERENCE: &str = "reference";
+        pub static CURRENT: &str = "current";
+    }
+    pub static ACCESS: &str = "access";
+    pub static MODIFICATION: &str = "modification";
+    pub static NO_CREATE: &str = "no-create";
+    pub static NO_DEREF: &str = "no-dereference";
+    pub static TIME: &str = "time";
+}
+
+static ARG_FILES: &str = "files";
+
+fn to_local(mut tm: time::Tm) -> time::Tm {
+    tm.tm_utcoff = time::now().tm_utcoff;
+    tm
+}
+
+fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
+    let ts = tm.to_timespec();
+    FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [USER]", uucore::execution_phrase())
+}
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let files = matches.values_of_os(ARG_FILES).unwrap();
+
+    let (mut atime, mut mtime) =
+        if let Some(reference) = matches.value_of_os(options::sources::REFERENCE) {
+            stat(Path::new(reference), !matches.is_present(options::NO_DEREF))?
+        } else {
+            let timestamp = if let Some(date) = matches.value_of(options::sources::DATE) {
+                parse_date(date)?
+            } else if let Some(current) = matches.value_of(options::sources::CURRENT) {
+                parse_timestamp(current)?
+            } else {
+                local_tm_to_filetime(time::now())
+            };
+            (timestamp, timestamp)
+        };
+
+    for filename in files {
+        let path = Path::new(filename);
+        if !path.exists() {
+            // no-dereference included here for compatibility
+            if matches.is_present(options::NO_CREATE) || matches.is_present(options::NO_DEREF) {
+                continue;
+            }
+
+            if let Err(e) = File::create(path) {
+                show!(e.map_err_context(|| format!("cannot touch '{}'", path.display())));
+                continue;
+            };
+
+            // Minor optimization: if no reference time was specified, we're done.
+            if !matches.is_present(options::SOURCES) {
+                continue;
+            }
+        }
+
+        // If changing "only" atime or mtime, grab the existing value of the other.
+        // Note that "-a" and "-m" may be passed together; this is not an xor.
+        if matches.is_present(options::ACCESS)
+            || matches.is_present(options::MODIFICATION)
+            || matches.is_present(options::TIME)
+        {
+            let st = stat(path, !matches.is_present(options::NO_DEREF))?;
+            let time = matches.value_of(options::TIME).unwrap_or("");
+
+            if !(matches.is_present(options::ACCESS)
+                || time.contains(&"access".to_owned())
+                || time.contains(&"atime".to_owned())
+                || time.contains(&"use".to_owned()))
+            {
+                atime = st.0;
+            }
+
+            if !(matches.is_present(options::MODIFICATION)
+                || time.contains(&"modify".to_owned())
+                || time.contains(&"mtime".to_owned()))
+            {
+                mtime = st.1;
+            }
+        }
+
+        if matches.is_present(options::NO_DEREF) {
+            set_symlink_file_times(path, atime, mtime)
+        } else {
+            filetime::set_file_times(path, atime, mtime)
+        }
+        .map_err_context(|| format!("setting times of '{}'", path.display()))?;
+    }
+
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::ACCESS)
+                .short("a")
+                .help("change only the access time"),
+        )
+        .arg(
+            Arg::with_name(options::sources::CURRENT)
+                .short("t")
+                .help("use [[CC]YY]MMDDhhmm[.ss] instead of the current time")
+                .value_name("STAMP")
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(options::sources::DATE)
+                .short("d")
+                .long(options::sources::DATE)
+                .help("parse argument and use it instead of current time")
+                .value_name("STRING"),
+        )
+        .arg(
+            Arg::with_name(options::MODIFICATION)
+                .short("m")
+                .help("change only the modification time"),
+        )
+        .arg(
+            Arg::with_name(options::NO_CREATE)
+                .short("c")
+                .long(options::NO_CREATE)
+                .help("do not create any files"),
+        )
+        .arg(
+            Arg::with_name(options::NO_DEREF)
+                .short("h")
+                .long(options::NO_DEREF)
+                .help(
+                    "affect each symbolic link instead of any referenced file \
+                     (only for systems that can change the timestamps of a symlink)",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::sources::REFERENCE)
+                .short("r")
+                .long(options::sources::REFERENCE)
+                .help("use this file's times instead of the current time")
+                .value_name("FILE"),
+        )
+        .arg(
+            Arg::with_name(options::TIME)
+                .long(options::TIME)
+                .help(
+                    "change only the specified time: \"access\", \"atime\", or \
+                     \"use\" are equivalent to -a; \"modify\" or \"mtime\" are \
+                     equivalent to -m",
+                )
+                .value_name("WORD")
+                .possible_values(&["access", "atime", "use"])
+                .takes_value(true),
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1),
+        )
+        .group(ArgGroup::with_name(options::SOURCES).args(&[
+            options::sources::CURRENT,
+            options::sources::DATE,
+            options::sources::REFERENCE,
+        ]))
+}
+
+fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> {
+    let metadata = if follow {
+        fs::symlink_metadata(path)
+    } else {
+        fs::metadata(path)
+    }
+    .map_err_context(|| format!("failed to get attributes of '{}'", path.display()))?;
+
+    Ok((
+        FileTime::from_last_access_time(&metadata),
+        FileTime::from_last_modification_time(&metadata),
+    ))
+}
+
+fn parse_date(str: &str) -> UResult<FileTime> {
+    // This isn't actually compatible with GNU touch, but there doesn't seem to
+    // be any simple specification for what format this parameter allows and I'm
+    // not about to implement GNU parse_datetime.
+    // http://git.savannah.gnu.org/gitweb/?p=gnulib.git;a=blob_plain;f=lib/parse-datetime.y
+    let formats = vec!["%c", "%F"];
+    for f in formats {
+        if let Ok(tm) = time::strptime(str, f) {
+            return Ok(local_tm_to_filetime(to_local(tm)));
+        }
+    }
+
+    if let Ok(tm) = time::strptime(str, "@%s") {
+        // Don't convert to local time in this case - seconds since epoch are not time-zone dependent
+        return Ok(local_tm_to_filetime(tm));
+    }
+
+    Err(USimpleError::new(
+        1,
+        format!("Unable to parse date: {}", str),
+    ))
+}
+
+fn parse_timestamp(s: &str) -> UResult<FileTime> {
+    let now = time::now();
+    let (format, ts) = match s.chars().count() {
+        15 => ("%Y%m%d%H%M.%S", s.to_owned()),
+        12 => ("%Y%m%d%H%M", s.to_owned()),
+        13 => ("%y%m%d%H%M.%S", s.to_owned()),
+        10 => ("%y%m%d%H%M", s.to_owned()),
+        11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
+        8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
+        _ => return Err(USimpleError::new(1, format!("invalid date format '{}'", s))),
+    };
+
+    let tm = time::strptime(&ts, format)
+        .map_err(|_| USimpleError::new(1, format!("invalid date format '{}'", s)))?;
+
+    let mut local = to_local(tm);
+    local.tm_isdst = -1;
+    let ft = local_tm_to_filetime(local);
+
+    // We have to check that ft is valid time. Due to daylight saving
+    // time switch, local time can jump from 1:59 AM to 3:00 AM,
+    // in which case any time between 2:00 AM and 2:59 AM is not valid.
+    // Convert back to local time and see if we got the same value back.
+    let ts = time::Timespec {
+        sec: ft.unix_seconds(),
+        nsec: 0,
+    };
+    let tm2 = time::at(ts);
+    if tm.tm_hour != tm2.tm_hour {
+        return Err(USimpleError::new(1, format!("invalid date format '{}'", s)));
+    }
+
+    Ok(ft)
+}
+
+
\ No newline at end of file diff --git a/src/uu_tr/expand.rs.html b/src/uu_tr/expand.rs.html new file mode 100644 index 000000000..e725f7433 --- /dev/null +++ b/src/uu_tr/expand.rs.html @@ -0,0 +1,297 @@ +expand.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Gehring <mg@ebfe.org>
+//  * (c) kwantam <kwantam@gmail.com>
+//  *     * 2015-04-28 ~ created `expand` module to eliminate most allocs during setup
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) allocs slen unesc
+
+use std::char::from_u32;
+use std::cmp::min;
+use std::iter::Peekable;
+use std::ops::RangeInclusive;
+
+/// Parse a backslash escape sequence to the corresponding character. Assumes
+/// the string starts from the character _after_ the `\` and is not empty.
+///
+/// Returns a tuple containing the character and the number of characters
+/// consumed from the input. The alphabetic escape sequences consume 1
+/// character; octal escape sequences consume 1 to 3 octal digits.
+#[inline]
+fn parse_sequence(s: &str) -> (char, usize) {
+    let mut s = s.chars();
+    let c = s.next().expect("invalid escape: empty string");
+
+    if ('0'..='7').contains(&c) {
+        let mut v = c.to_digit(8).unwrap();
+        let mut consumed = 1;
+        let bits_per_digit = 3;
+
+        for c in s.take(2) {
+            match c.to_digit(8) {
+                Some(c) => {
+                    v = (v << bits_per_digit) | c;
+                    consumed += 1;
+                }
+                None => break,
+            }
+        }
+
+        (from_u32(v).expect("invalid octal escape"), consumed)
+    } else {
+        (
+            match c {
+                'a' => 0x07u8 as char,
+                'b' => 0x08u8 as char,
+                'f' => 0x0cu8 as char,
+                'v' => 0x0bu8 as char,
+                'n' => '\n',
+                'r' => '\r',
+                't' => '\t',
+                c => c,
+            },
+            1,
+        )
+    }
+}
+
+struct Unescape<'a> {
+    string: &'a str,
+}
+
+impl<'a> Iterator for Unescape<'a> {
+    type Item = char;
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        let slen = self.string.len();
+        (min(slen, 1), None)
+    }
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.string.is_empty() {
+            return None;
+        }
+
+        // is the next character an escape?
+        let (ret, idx) = match self.string.chars().next().unwrap() {
+            '\\' if self.string.len() > 1 => {
+                // yes---it's \ and it's not the last char in a string
+                // we know that \ is 1 byte long so we can index into the string safely
+                let (c, consumed) = parse_sequence(&self.string[1..]);
+
+                (Some(c), 1 + consumed)
+            }
+            c => (Some(c), c.len_utf8()), // not an escape char
+        };
+
+        self.string = &self.string[idx..]; // advance the pointer to the next char
+        ret
+    }
+}
+
+pub struct ExpandSet<'a> {
+    range: RangeInclusive<u32>,
+    unesc: Peekable<Unescape<'a>>,
+}
+
+impl<'a> Iterator for ExpandSet<'a> {
+    type Item = char;
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.unesc.size_hint()
+    }
+
+    #[inline]
+    fn next(&mut self) -> Option<Self::Item> {
+        // while the Range has elements, try to return chars from it
+        // but make sure that they actually turn out to be Chars!
+        for n in &mut self.range {
+            if let Some(c) = from_u32(n) {
+                return Some(c);
+            }
+        }
+
+        if let Some(first) = self.unesc.next() {
+            // peek ahead
+            if self.unesc.peek() == Some(&'-') && self.unesc.size_hint().0 > 1 {
+                self.unesc.next(); // this is the '-'
+                let last = self.unesc.next().unwrap(); // this is the end of the range
+
+                {
+                    self.range = first as u32 + 1..=last as u32;
+                }
+            }
+
+            return Some(first); // in any case, return the next char
+        }
+
+        None
+    }
+}
+
+impl<'a> ExpandSet<'a> {
+    #[inline]
+    pub fn new(s: &'a str) -> ExpandSet<'a> {
+        ExpandSet {
+            range: 0..=0,
+            unesc: Unescape { string: s }.peekable(),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_tr/tr.rs.html b/src/uu_tr/tr.rs.html new file mode 100644 index 000000000..4407ae3e6 --- /dev/null +++ b/src/uu_tr/tr.rs.html @@ -0,0 +1,723 @@ +tr.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Michael Gehring <mg@ebfe.org>
+//  * (c) kwantam <kwantam@gmail.com>
+//  *     * 2015-04-28 ~ created `expand` module to eliminate most allocs during setup
+//  * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) allocs bset dflag cflag sflag tflag
+
+#[macro_use]
+extern crate uucore;
+
+mod expand;
+
+use bit_set::BitSet;
+use clap::{crate_version, App, Arg};
+use fnv::FnvHashMap;
+use std::io::{stdin, stdout, BufRead, BufWriter, Write};
+
+use crate::expand::ExpandSet;
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "translate or delete characters";
+
+const BUFFER_LEN: usize = 1024;
+
+mod options {
+    pub const COMPLEMENT: &str = "complement";
+    pub const DELETE: &str = "delete";
+    pub const SQUEEZE: &str = "squeeze-repeats";
+    pub const TRUNCATE: &str = "truncate";
+    pub const SETS: &str = "sets";
+}
+
+trait SymbolTranslator {
+    fn translate(&self, c: char, prev_c: char) -> Option<char>;
+}
+
+struct DeleteOperation {
+    bset: BitSet,
+    complement: bool,
+}
+
+impl DeleteOperation {
+    fn new(set: ExpandSet, complement: bool) -> DeleteOperation {
+        DeleteOperation {
+            bset: set.map(|c| c as usize).collect(),
+            complement,
+        }
+    }
+}
+
+impl SymbolTranslator for DeleteOperation {
+    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
+        let uc = c as usize;
+        if self.complement == self.bset.contains(uc) {
+            Some(c)
+        } else {
+            None
+        }
+    }
+}
+
+struct SqueezeOperation {
+    squeeze_set: BitSet,
+    complement: bool,
+}
+
+impl SqueezeOperation {
+    fn new(squeeze_set: ExpandSet, complement: bool) -> SqueezeOperation {
+        SqueezeOperation {
+            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
+            complement,
+        }
+    }
+}
+
+impl SymbolTranslator for SqueezeOperation {
+    fn translate(&self, c: char, prev_c: char) -> Option<char> {
+        if prev_c == c && self.complement != self.squeeze_set.contains(c as usize) {
+            None
+        } else {
+            Some(c)
+        }
+    }
+}
+
+struct DeleteAndSqueezeOperation {
+    delete_set: BitSet,
+    squeeze_set: BitSet,
+    complement: bool,
+}
+
+impl DeleteAndSqueezeOperation {
+    fn new(
+        delete_set: ExpandSet,
+        squeeze_set: ExpandSet,
+        complement: bool,
+    ) -> DeleteAndSqueezeOperation {
+        DeleteAndSqueezeOperation {
+            delete_set: delete_set.map(|c| c as usize).collect(),
+            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
+            complement,
+        }
+    }
+}
+
+impl SymbolTranslator for DeleteAndSqueezeOperation {
+    fn translate(&self, c: char, prev_c: char) -> Option<char> {
+        if self.complement != self.delete_set.contains(c as usize)
+            || prev_c == c && self.squeeze_set.contains(c as usize)
+        {
+            None
+        } else {
+            Some(c)
+        }
+    }
+}
+
+struct TranslateOperation {
+    translate_map: FnvHashMap<usize, char>,
+    complement: bool,
+    s2_last: char,
+}
+
+impl TranslateOperation {
+    fn new(
+        set1: ExpandSet,
+        set2: &mut ExpandSet,
+        truncate: bool,
+        complement: bool,
+    ) -> TranslateOperation {
+        let mut map = FnvHashMap::default();
+        let mut s2_prev = '_';
+        for i in set1 {
+            let s2_next = set2.next();
+
+            if s2_next.is_none() && truncate {
+                map.insert(i as usize, i);
+            } else {
+                s2_prev = s2_next.unwrap_or(s2_prev);
+                map.insert(i as usize, s2_prev);
+            }
+        }
+        TranslateOperation {
+            translate_map: map,
+            complement,
+            s2_last: set2.last().unwrap_or(s2_prev),
+        }
+    }
+}
+
+impl SymbolTranslator for TranslateOperation {
+    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
+        if self.complement {
+            Some(if self.translate_map.contains_key(&(c as usize)) {
+                c
+            } else {
+                self.s2_last
+            })
+        } else {
+            Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
+        }
+    }
+}
+
+struct TranslateAndSqueezeOperation {
+    translate: TranslateOperation,
+    squeeze: SqueezeOperation,
+}
+
+impl TranslateAndSqueezeOperation {
+    fn new(sets: Vec<String>, truncate: bool, complement: bool) -> TranslateAndSqueezeOperation {
+        let set1 = ExpandSet::new(sets[0].as_ref());
+        let set1_ = ExpandSet::new(sets[0].as_ref());
+        let mut set2 = ExpandSet::new(sets[1].as_ref());
+        let set2_ = ExpandSet::new(sets[1].as_ref());
+        TranslateAndSqueezeOperation {
+            translate: TranslateOperation::new(set1, &mut set2, truncate, complement),
+            squeeze: SqueezeOperation::new(if complement { set1_ } else { set2_ }, complement),
+        }
+    }
+}
+
+impl SymbolTranslator for TranslateAndSqueezeOperation {
+    fn translate(&self, c: char, prev_c: char) -> Option<char> {
+        // `unwrap()` will never panic because `Translate.translate()`
+        // always returns `Some`.
+        self.squeeze
+            .translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
+    }
+}
+
+fn translate_input<T: SymbolTranslator>(
+    input: &mut dyn BufRead,
+    output: &mut dyn Write,
+    translator: T,
+) {
+    let mut buf = String::with_capacity(BUFFER_LEN + 4);
+    let mut output_buf = String::with_capacity(BUFFER_LEN + 4);
+
+    while let Ok(length) = input.read_line(&mut buf) {
+        let mut prev_c = 0 as char;
+        if length == 0 {
+            break;
+        }
+        {
+            // isolation to make borrow checker happy
+            let filtered = buf.chars().filter_map(|c| {
+                let res = translator.translate(c, prev_c);
+                // Set `prev_c` to the post-translate character. This
+                // allows the squeeze operation to correctly function
+                // after the translate operation.
+                if let Some(rc) = res {
+                    prev_c = rc;
+                }
+                res
+            });
+
+            output_buf.extend(filtered);
+            output.write_all(output_buf.as_bytes()).unwrap();
+        }
+        buf.clear();
+        output_buf.clear();
+    }
+}
+
+fn usage() -> String {
+    format!("{} [OPTION]... SET1 [SET2]", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    "Translate, squeeze, and/or delete characters from standard input,
+writing to standard output."
+        .to_string()
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let usage = usage();
+    let after_help = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let delete_flag = matches.is_present(options::DELETE);
+    let complement_flag = matches.is_present(options::COMPLEMENT) || matches.is_present("C");
+    let squeeze_flag = matches.is_present(options::SQUEEZE);
+    let truncate_flag = matches.is_present(options::TRUNCATE);
+
+    let sets = matches
+        .values_of(options::SETS)
+        .map(|v| v.map(ToString::to_string).collect::<Vec<_>>())
+        .unwrap_or_default();
+
+    if sets.is_empty() {
+        show_error!(
+            "missing operand\nTry '{} --help' for more information.",
+            uucore::execution_phrase()
+        );
+        return 1;
+    }
+
+    if !(delete_flag || squeeze_flag) && sets.len() < 2 {
+        show_error!(
+            "missing operand after '{}'\nTry '{} --help' for more information.",
+            sets[0],
+            uucore::execution_phrase()
+        );
+        return 1;
+    }
+
+    let stdin = stdin();
+    let mut locked_stdin = stdin.lock();
+    let stdout = stdout();
+    let locked_stdout = stdout.lock();
+    let mut buffered_stdout = BufWriter::new(locked_stdout);
+
+    let set1 = ExpandSet::new(sets[0].as_ref());
+    if delete_flag {
+        if squeeze_flag {
+            let set2 = ExpandSet::new(sets[1].as_ref());
+            let op = DeleteAndSqueezeOperation::new(set1, set2, complement_flag);
+            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
+        } else {
+            let op = DeleteOperation::new(set1, complement_flag);
+            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
+        }
+    } else if squeeze_flag {
+        if sets.len() < 2 {
+            let op = SqueezeOperation::new(set1, complement_flag);
+            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
+        } else {
+            let op = TranslateAndSqueezeOperation::new(sets, truncate_flag, complement_flag);
+            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
+        }
+    } else {
+        let mut set2 = ExpandSet::new(sets[1].as_ref());
+        let op = TranslateOperation::new(set1, &mut set2, truncate_flag, complement_flag);
+        translate_input(&mut locked_stdin, &mut buffered_stdout, op);
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::COMPLEMENT)
+                // .visible_short_alias('C')  // TODO: requires clap "3.0.0-beta.2"
+                .short("c")
+                .long(options::COMPLEMENT)
+                .help("use the complement of SET1"),
+        )
+        .arg(
+            Arg::with_name("C") // work around for `Arg::visible_short_alias`
+                .short("C")
+                .help("same as -c"),
+        )
+        .arg(
+            Arg::with_name(options::DELETE)
+                .short("d")
+                .long(options::DELETE)
+                .help("delete characters in SET1, do not translate"),
+        )
+        .arg(
+            Arg::with_name(options::SQUEEZE)
+                .long(options::SQUEEZE)
+                .short("s")
+                .help(
+                    "replace each sequence  of  a  repeated  character  that  is
+  listed  in the last specified SET, with a single occurrence
+  of that character",
+                ),
+        )
+        .arg(
+            Arg::with_name(options::TRUNCATE)
+                .long(options::TRUNCATE)
+                .short("t")
+                .help("first truncate SET1 to length of SET2"),
+        )
+        .arg(
+            Arg::with_name(options::SETS)
+                .multiple(true)
+                .takes_value(true)
+                .min_values(1)
+                .max_values(2),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_true/true.rs.html b/src/uu_true/true.rs.html new file mode 100644 index 000000000..babaae15a --- /dev/null +++ b/src/uu_true/true.rs.html @@ -0,0 +1,49 @@ +true.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::App;
+use uucore::error::UResult;
+
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    uu_app().get_matches_from(args);
+    Ok(())
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+}
+
+
\ No newline at end of file diff --git a/src/uu_truncate/truncate.rs.html b/src/uu_truncate/truncate.rs.html new file mode 100644 index 000000000..14a289843 --- /dev/null +++ b/src/uu_truncate/truncate.rs.html @@ -0,0 +1,747 @@ +truncate.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Alex Lyon <arcterus@mail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) RFILE refsize rfilename fsize tsize
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::convert::TryFrom;
+use std::fs::{metadata, OpenOptions};
+use std::io::ErrorKind;
+use std::path::Path;
+use uucore::parse_size::{parse_size, ParseSizeError};
+
+#[derive(Debug, Eq, PartialEq)]
+enum TruncateMode {
+    Absolute(usize),
+    Extend(usize),
+    Reduce(usize),
+    AtMost(usize),
+    AtLeast(usize),
+    RoundDown(usize),
+    RoundUp(usize),
+}
+
+impl TruncateMode {
+    /// Compute a target size in bytes for this truncate mode.
+    ///
+    /// `fsize` is the size of the reference file, in bytes.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,ignore
+    /// let mode = TruncateMode::Extend(5);
+    /// let fsize = 10;
+    /// assert_eq!(mode.to_size(fsize), 15);
+    /// ```
+    fn to_size(&self, fsize: usize) -> usize {
+        match self {
+            TruncateMode::Absolute(size) => *size,
+            TruncateMode::Extend(size) => fsize + size,
+            TruncateMode::Reduce(size) => fsize - size,
+            TruncateMode::AtMost(size) => fsize.min(*size),
+            TruncateMode::AtLeast(size) => fsize.max(*size),
+            TruncateMode::RoundDown(size) => fsize - fsize % size,
+            TruncateMode::RoundUp(size) => fsize + fsize % size,
+        }
+    }
+}
+
+static ABOUT: &str = "Shrink or extend the size of each file to the specified size.";
+
+pub mod options {
+    pub static IO_BLOCKS: &str = "io-blocks";
+    pub static NO_CREATE: &str = "no-create";
+    pub static REFERENCE: &str = "reference";
+    pub static SIZE: &str = "size";
+    pub static ARG_FILES: &str = "files";
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    String::from(
+        "
+    SIZE is an integer with an optional prefix and optional unit.
+    The available units (K, M, G, T, P, E, Z, and Y) use the following format:
+        'KB' =>           1000 (kilobytes)
+        'K'  =>           1024 (kibibytes)
+        'MB' =>      1000*1000 (megabytes)
+        'M'  =>      1024*1024 (mebibytes)
+        'GB' => 1000*1000*1000 (gigabytes)
+        'G'  => 1024*1024*1024 (gibibytes)
+    SIZE may also be prefixed by one of the following to adjust the size of each
+    file based on its current size:
+        '+'  => extend by
+        '-'  => reduce by
+        '<'  => at most
+        '>'  => at least
+        '/'  => round down to multiple of
+        '%'  => round up to multiple of",
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let long_usage = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&long_usage[..])
+        .get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(options::ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    if files.is_empty() {
+        show_error!("Missing an argument");
+        return 1;
+    } else {
+        let io_blocks = matches.is_present(options::IO_BLOCKS);
+        let no_create = matches.is_present(options::NO_CREATE);
+        let reference = matches.value_of(options::REFERENCE).map(String::from);
+        let size = matches.value_of(options::SIZE).map(String::from);
+        if let Err(e) = truncate(no_create, io_blocks, reference, size, files) {
+            match e.kind() {
+                ErrorKind::NotFound => {
+                    // TODO Improve error-handling so that the error
+                    // returned by `truncate()` provides the necessary
+                    // parameter for formatting the error message.
+                    let reference = matches.value_of(options::REFERENCE).map(String::from);
+                    crash!(
+                        1,
+                        "cannot stat '{}': No such file or directory",
+                        reference.unwrap_or_else(|| "".to_string())
+                    ); // TODO: fix '--no-create' see test_reference and test_truncate_bytes_size
+                }
+                _ => crash!(1, "{}", e.to_string()),
+            }
+        }
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::IO_BLOCKS)
+            .short("o")
+            .long(options::IO_BLOCKS)
+            .help("treat SIZE as the number of I/O blocks of the file rather than bytes (NOT IMPLEMENTED)")
+        )
+        .arg(
+            Arg::with_name(options::NO_CREATE)
+            .short("c")
+            .long(options::NO_CREATE)
+            .help("do not create files that do not exist")
+        )
+        .arg(
+            Arg::with_name(options::REFERENCE)
+            .short("r")
+            .long(options::REFERENCE)
+            .required_unless(options::SIZE)
+            .help("base the size of each file on the size of RFILE")
+            .value_name("RFILE")
+        )
+        .arg(
+            Arg::with_name(options::SIZE)
+            .short("s")
+            .long(options::SIZE)
+            .required_unless(options::REFERENCE)
+            .help("set or adjust the size of each file according to SIZE, which is in bytes unless --io-blocks is specified")
+            .value_name("SIZE")
+        )
+        .arg(Arg::with_name(options::ARG_FILES)
+             .value_name("FILE")
+             .multiple(true)
+             .takes_value(true)
+             .required(true)
+             .min_values(1))
+}
+
+/// Truncate the named file to the specified size.
+///
+/// If `create` is true, then the file will be created if it does not
+/// already exist. If `size` is larger than the number of bytes in the
+/// file, then the file will be padded with zeros. If `size` is smaller
+/// than the number of bytes in the file, then the file will be
+/// truncated and any bytes beyond `size` will be lost.
+///
+/// # Errors
+///
+/// If the file could not be opened, or there was a problem setting the
+/// size of the file.
+fn file_truncate(filename: &str, create: bool, size: usize) -> std::io::Result<()> {
+    let path = Path::new(filename);
+    let f = OpenOptions::new().write(true).create(create).open(path)?;
+    f.set_len(u64::try_from(size).unwrap())
+}
+
+/// Truncate files to a size relative to a given file.
+///
+/// `rfilename` is the name of the reference file.
+///
+/// `size_string` gives the size relative to the reference file to which
+/// to set the target files. For example, "+3K" means "set each file to
+/// be three kilobytes larger than the size of the reference file".
+///
+/// If `create` is true, then each file will be created if it does not
+/// already exist.
+///
+/// # Errors
+///
+/// If the any file could not be opened, or there was a problem setting
+/// the size of at least one file.
+fn truncate_reference_and_size(
+    rfilename: &str,
+    size_string: &str,
+    filenames: Vec<String>,
+    create: bool,
+) -> std::io::Result<()> {
+    let mode = match parse_mode_and_size(size_string) {
+        Ok(m) => match m {
+            TruncateMode::Absolute(_) => {
+                crash!(1, "you must specify a relative '--size' with '--reference'")
+            }
+            _ => m,
+        },
+        Err(e) => crash!(1, "Invalid number: {}", e.to_string()),
+    };
+    let fsize = usize::try_from(metadata(rfilename)?.len()).unwrap();
+    let tsize = mode.to_size(fsize);
+    for filename in &filenames {
+        file_truncate(filename, create, tsize)?;
+    }
+    Ok(())
+}
+
+/// Truncate files to match the size of a given reference file.
+///
+/// `rfilename` is the name of the reference file.
+///
+/// If `create` is true, then each file will be created if it does not
+/// already exist.
+///
+/// # Errors
+///
+/// If the any file could not be opened, or there was a problem setting
+/// the size of at least one file.
+fn truncate_reference_file_only(
+    rfilename: &str,
+    filenames: Vec<String>,
+    create: bool,
+) -> std::io::Result<()> {
+    let tsize = usize::try_from(metadata(rfilename)?.len()).unwrap();
+    for filename in &filenames {
+        file_truncate(filename, create, tsize)?;
+    }
+    Ok(())
+}
+
+/// Truncate files to a specified size.
+///
+/// `size_string` gives either an absolute size or a relative size. A
+/// relative size adjusts the size of each file relative to its current
+/// size. For example, "3K" means "set each file to be three kilobytes"
+/// whereas "+3K" means "set each file to be three kilobytes larger than
+/// its current size".
+///
+/// If `create` is true, then each file will be created if it does not
+/// already exist.
+///
+/// # Errors
+///
+/// If the any file could not be opened, or there was a problem setting
+/// the size of at least one file.
+fn truncate_size_only(
+    size_string: &str,
+    filenames: Vec<String>,
+    create: bool,
+) -> std::io::Result<()> {
+    let mode = match parse_mode_and_size(size_string) {
+        Ok(m) => m,
+        Err(e) => crash!(1, "Invalid number: {}", e.to_string()),
+    };
+    for filename in &filenames {
+        let fsize = usize::try_from(metadata(filename)?.len()).unwrap();
+        let tsize = mode.to_size(fsize);
+        file_truncate(filename, create, tsize)?;
+    }
+    Ok(())
+}
+
+fn truncate(
+    no_create: bool,
+    _: bool,
+    reference: Option<String>,
+    size: Option<String>,
+    filenames: Vec<String>,
+) -> std::io::Result<()> {
+    let create = !no_create;
+    // There are four possibilities
+    // - reference file given and size given,
+    // - reference file given but no size given,
+    // - no reference file given but size given,
+    // - no reference file given and no size given,
+    match (reference, size) {
+        (Some(rfilename), Some(size_string)) => {
+            truncate_reference_and_size(&rfilename, &size_string, filenames, create)
+        }
+        (Some(rfilename), None) => truncate_reference_file_only(&rfilename, filenames, create),
+        (None, Some(size_string)) => truncate_size_only(&size_string, filenames, create),
+        (None, None) => crash!(1, "you must specify either --reference or --size"), // this case cannot happen anymore because it's handled by clap
+    }
+}
+
+/// Decide whether a character is one of the size modifiers, like '+' or '<'.
+fn is_modifier(c: char) -> bool {
+    c == '+' || c == '-' || c == '<' || c == '>' || c == '/' || c == '%'
+}
+
+/// Parse a size string with optional modifier symbol as its first character.
+///
+/// A size string is as described in [`parse_size`]. The first character
+/// of `size_string` might be a modifier symbol, like `'+'` or
+/// `'<'`. The first element of the pair returned by this function
+/// indicates which modifier symbol was present, or
+/// [`TruncateMode::Absolute`] if none.
+///
+/// # Panics
+///
+/// If `size_string` is empty, or if no number could be parsed from the
+/// given string (for example, if the string were `"abc"`).
+///
+/// # Examples
+///
+/// ```rust,ignore
+/// assert_eq!(parse_mode_and_size("+123"), (TruncateMode::Extend, 123));
+/// ```
+fn parse_mode_and_size(size_string: &str) -> Result<TruncateMode, ParseSizeError> {
+    // Trim any whitespace.
+    let mut size_string = size_string.trim();
+
+    // Get the modifier character from the size string, if any. For
+    // example, if the argument is "+123", then the modifier is '+'.
+    if let Some(c) = size_string.chars().next() {
+        if is_modifier(c) {
+            size_string = &size_string[1..];
+        }
+        parse_size(size_string).map(match c {
+            '+' => TruncateMode::Extend,
+            '-' => TruncateMode::Reduce,
+            '<' => TruncateMode::AtMost,
+            '>' => TruncateMode::AtLeast,
+            '/' => TruncateMode::RoundDown,
+            '%' => TruncateMode::RoundUp,
+            _ => TruncateMode::Absolute,
+        })
+    } else {
+        Err(ParseSizeError::ParseFailure(size_string.to_string()))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::parse_mode_and_size;
+    use crate::TruncateMode;
+
+    #[test]
+    fn test_parse_mode_and_size() {
+        assert_eq!(parse_mode_and_size("10"), Ok(TruncateMode::Absolute(10)));
+        assert_eq!(parse_mode_and_size("+10"), Ok(TruncateMode::Extend(10)));
+        assert_eq!(parse_mode_and_size("-10"), Ok(TruncateMode::Reduce(10)));
+        assert_eq!(parse_mode_and_size("<10"), Ok(TruncateMode::AtMost(10)));
+        assert_eq!(parse_mode_and_size(">10"), Ok(TruncateMode::AtLeast(10)));
+        assert_eq!(parse_mode_and_size("/10"), Ok(TruncateMode::RoundDown(10)));
+        assert_eq!(parse_mode_and_size("%10"), Ok(TruncateMode::RoundUp(10)));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_tsort/tsort.rs.html b/src/uu_tsort/tsort.rs.html new file mode 100644 index 000000000..e4d23506e --- /dev/null +++ b/src/uu_tsort/tsort.rs.html @@ -0,0 +1,377 @@ +tsort.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Ben Eggers <ben.eggers36@gmail.com>
+//  * (c) Akira Hayakawa <ruby.wktk@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use std::collections::{HashMap, HashSet};
+use std::fs::File;
+use std::io::{stdin, BufRead, BufReader, Read};
+use std::path::Path;
+use uucore::InvalidEncodingHandling;
+
+static SUMMARY: &str = "Topological sort the strings in FILE.
+Strings are defined as any sequence of tokens separated by whitespace (tab, space, or newline).
+If FILE is not passed in, stdin is used instead.";
+static USAGE: &str = "tsort [OPTIONS] FILE";
+
+mod options {
+    pub const FILE: &str = "file";
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    let input = matches
+        .value_of(options::FILE)
+        .expect("Value is required by clap");
+
+    let mut stdin_buf;
+    let mut file_buf;
+    let mut reader = BufReader::new(if input == "-" {
+        stdin_buf = stdin();
+        &mut stdin_buf as &mut dyn Read
+    } else {
+        file_buf = match File::open(Path::new(&input)) {
+            Ok(a) => a,
+            _ => {
+                show_error!("{}: No such file or directory", input);
+                return 1;
+            }
+        };
+        &mut file_buf as &mut dyn Read
+    });
+
+    let mut g = Graph::new();
+    loop {
+        let mut line = String::new();
+        match reader.read_line(&mut line) {
+            Ok(_) => {
+                let tokens: Vec<String> = line
+                    .trim_end()
+                    .split_whitespace()
+                    .map(|s| s.to_owned())
+                    .collect();
+                if tokens.is_empty() {
+                    break;
+                }
+                for ab in tokens.chunks(2) {
+                    match ab.len() {
+                        2 => g.add_edge(&ab[0], &ab[1]),
+                        _ => crash!(1, "{}: input contains an odd number of tokens", input),
+                    }
+                }
+            }
+            _ => break,
+        }
+    }
+
+    g.run_tsort();
+
+    if !g.is_acyclic() {
+        crash!(1, "{}, input contains a loop:", input);
+    }
+
+    for x in &g.result {
+        println!("{}", x);
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .usage(USAGE)
+        .about(SUMMARY)
+        .arg(
+            Arg::with_name(options::FILE)
+                .default_value("-")
+                .hidden(true),
+        )
+}
+
+// We use String as a representation of node here
+// but using integer may improve performance.
+struct Graph {
+    in_edges: HashMap<String, HashSet<String>>,
+    out_edges: HashMap<String, Vec<String>>,
+    result: Vec<String>,
+}
+
+impl Graph {
+    fn new() -> Graph {
+        Graph {
+            in_edges: HashMap::new(),
+            out_edges: HashMap::new(),
+            result: vec![],
+        }
+    }
+
+    fn has_node(&self, n: &str) -> bool {
+        self.in_edges.contains_key(n)
+    }
+
+    fn has_edge(&self, from: &str, to: &str) -> bool {
+        self.in_edges[to].contains(from)
+    }
+
+    fn init_node(&mut self, n: &str) {
+        self.in_edges.insert(n.to_string(), HashSet::new());
+        self.out_edges.insert(n.to_string(), vec![]);
+    }
+
+    fn add_edge(&mut self, from: &str, to: &str) {
+        if !self.has_node(to) {
+            self.init_node(to);
+        }
+
+        if !self.has_node(from) {
+            self.init_node(from);
+        }
+
+        if from != to && !self.has_edge(from, to) {
+            self.in_edges.get_mut(to).unwrap().insert(from.to_string());
+            self.out_edges.get_mut(from).unwrap().push(to.to_string());
+        }
+    }
+
+    // Kahn's algorithm
+    // O(|V|+|E|)
+    fn run_tsort(&mut self) {
+        let mut start_nodes = vec![];
+        for (n, edges) in &self.in_edges {
+            if edges.is_empty() {
+                start_nodes.push(n.clone());
+            }
+        }
+
+        while !start_nodes.is_empty() {
+            let n = start_nodes.remove(0);
+
+            self.result.push(n.clone());
+
+            let n_out_edges = self.out_edges.get_mut(&n).unwrap();
+            for m in n_out_edges.iter() {
+                let m_in_edges = self.in_edges.get_mut(m).unwrap();
+                m_in_edges.remove(&n);
+
+                // If m doesn't have other in-coming edges add it to start_nodes
+                if m_in_edges.is_empty() {
+                    start_nodes.push(m.clone());
+                }
+            }
+            n_out_edges.clear();
+        }
+    }
+
+    fn is_acyclic(&self) -> bool {
+        for edges in self.out_edges.values() {
+            if !edges.is_empty() {
+                return false;
+            }
+        }
+        true
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_tty/tty.rs.html b/src/uu_tty/tty.rs.html new file mode 100644 index 000000000..9d279c9a3 --- /dev/null +++ b/src/uu_tty/tty.rs.html @@ -0,0 +1,183 @@ +tty.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+//  *
+//  * Synced with http://lingrok.org/xref/coreutils/src/tty.c
+
+// spell-checker:ignore (ToDO) ttyname filedesc
+
+use clap::{crate_version, App, Arg};
+use std::ffi::CStr;
+use std::io::Write;
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Print the file name of the terminal connected to standard input.";
+
+mod options {
+    pub const SILENT: &str = "silent";
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from_safe(args);
+
+    let matches = match matches {
+        Ok(m) => m,
+        Err(e) => {
+            eprint!("{}", e);
+            return 2;
+        }
+    };
+
+    let silent = matches.is_present(options::SILENT);
+
+    // Call libc function ttyname
+    let tty = unsafe {
+        let ptr = libc::ttyname(libc::STDIN_FILENO);
+        if !ptr.is_null() {
+            String::from_utf8_lossy(CStr::from_ptr(ptr).to_bytes()).to_string()
+        } else {
+            "".to_owned()
+        }
+    };
+
+    let mut stdout = std::io::stdout();
+
+    if !silent {
+        let write_result = if !tty.chars().all(|c| c.is_whitespace()) {
+            writeln!(stdout, "{}", tty)
+        } else {
+            writeln!(stdout, "not a tty")
+        };
+        if write_result.is_err() || stdout.flush().is_err() {
+            // Don't return to prevent a panic later when another flush is attempted
+            // because the `uucore_procs::main` macro inserts a flush after execution for every utility.
+            std::process::exit(3);
+        }
+    }
+
+    if atty::is(atty::Stream::Stdin) {
+        libc::EXIT_SUCCESS
+    } else {
+        libc::EXIT_FAILURE
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::SILENT)
+                .long(options::SILENT)
+                .visible_alias("quiet")
+                .short("s")
+                .help("print nothing, only return an exit status")
+                .required(false),
+        )
+}
+
+
\ No newline at end of file diff --git a/src/uu_uname/uname.rs.html b/src/uu_uname/uname.rs.html new file mode 100644 index 000000000..0b23986ad --- /dev/null +++ b/src/uu_uname/uname.rs.html @@ -0,0 +1,331 @@ +uname.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Joao Oliveira <joaoxsouls@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// last synced with: uname (GNU coreutils) 8.21
+
+// spell-checker:ignore (ToDO) nodename kernelname kernelrelease kernelversion sysname hwplatform mnrsv
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use platform_info::*;
+
+const ABOUT: &str = "Print certain system information.  With no OPTION, same as -s.";
+
+pub mod options {
+    pub static ALL: &str = "all";
+    pub static KERNELNAME: &str = "kernel-name";
+    pub static NODENAME: &str = "nodename";
+    pub static KERNELVERSION: &str = "kernel-version";
+    pub static KERNELRELEASE: &str = "kernel-release";
+    pub static MACHINE: &str = "machine";
+    pub static PROCESSOR: &str = "processor";
+    pub static HWPLATFORM: &str = "hardware-platform";
+    pub static OS: &str = "operating-system";
+}
+
+#[cfg(all(target_os = "linux", any(target_env = "gnu", target_env = "")))]
+const HOST_OS: &str = "GNU/Linux";
+#[cfg(all(target_os = "linux", not(any(target_env = "gnu", target_env = ""))))]
+const HOST_OS: &str = "Linux";
+#[cfg(target_os = "windows")]
+const HOST_OS: &str = "Windows NT";
+#[cfg(target_os = "freebsd")]
+const HOST_OS: &str = "FreeBSD";
+#[cfg(target_os = "netbsd")]
+const HOST_OS: &str = "NetBSD";
+#[cfg(target_os = "openbsd")]
+const HOST_OS: &str = "OpenBSD";
+#[cfg(target_vendor = "apple")]
+const HOST_OS: &str = "Darwin";
+#[cfg(target_os = "fuchsia")]
+const HOST_OS: &str = "Fuchsia";
+#[cfg(target_os = "redox")]
+const HOST_OS: &str = "Redox";
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = format!("{} [OPTION]...", uucore::execution_phrase());
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let uname = return_if_err!(1, PlatformInfo::new());
+    let mut output = String::new();
+
+    let all = matches.is_present(options::ALL);
+    let kernelname = matches.is_present(options::KERNELNAME);
+    let nodename = matches.is_present(options::NODENAME);
+    let kernelrelease = matches.is_present(options::KERNELRELEASE);
+    let kernelversion = matches.is_present(options::KERNELVERSION);
+    let machine = matches.is_present(options::MACHINE);
+    let processor = matches.is_present(options::PROCESSOR);
+    let hwplatform = matches.is_present(options::HWPLATFORM);
+    let os = matches.is_present(options::OS);
+
+    let none = !(all
+        || kernelname
+        || nodename
+        || kernelrelease
+        || kernelversion
+        || machine
+        || os
+        || processor
+        || hwplatform);
+
+    if kernelname || all || none {
+        output.push_str(&uname.sysname());
+        output.push(' ');
+    }
+
+    if nodename || all {
+        output.push_str(&uname.nodename());
+        output.push(' ');
+    }
+    if kernelrelease || all {
+        output.push_str(&uname.release());
+        output.push(' ');
+    }
+    if kernelversion || all {
+        output.push_str(&uname.version());
+        output.push(' ');
+    }
+    if machine || all {
+        output.push_str(&uname.machine());
+        output.push(' ');
+    }
+    if processor || all {
+        // According to https://stackoverflow.com/posts/394271/revisions
+        // Most of the time, it returns unknown
+        output.push_str("unknown");
+        output.push(' ');
+    }
+    if hwplatform || all {
+        // According to https://lists.gnu.org/archive/html/bug-coreutils/2005-09/msg00063.html
+        // Most of the time, it returns unknown
+        output.push_str("unknown");
+        output.push(' ');
+    }
+    if os || all {
+        output.push_str(HOST_OS);
+        output.push(' ');
+    }
+    println!("{}", output.trim_end());
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(Arg::with_name(options::ALL)
+            .short("a")
+            .long(options::ALL)
+            .help("Behave as though all of the options -mnrsv were specified."))
+        .arg(Arg::with_name(options::KERNELNAME)
+            .short("s")
+            .long(options::KERNELNAME)
+            .alias("sysname") // Obsolescent option in GNU uname
+            .help("print the kernel name."))
+        .arg(Arg::with_name(options::NODENAME)
+            .short("n")
+            .long(options::NODENAME)
+            .help("print the nodename (the nodename may be a name that the system is known by to a communications network)."))
+        .arg(Arg::with_name(options::KERNELRELEASE)
+            .short("r")
+            .long(options::KERNELRELEASE)
+            .alias("release") // Obsolescent option in GNU uname
+            .help("print the operating system release."))
+        .arg(Arg::with_name(options::KERNELVERSION)
+            .short("v")
+            .long(options::KERNELVERSION)
+            .help("print the operating system version."))
+        .arg(Arg::with_name(options::HWPLATFORM)
+            .short("i")
+            .long(options::HWPLATFORM)
+            .help("print the hardware platform (non-portable)"))
+        .arg(Arg::with_name(options::MACHINE)
+            .short("m")
+            .long(options::MACHINE)
+            .help("print the machine hardware name."))
+        .arg(Arg::with_name(options::PROCESSOR)
+            .short("p")
+            .long(options::PROCESSOR)
+            .help("print the processor type (non-portable)"))
+        .arg(Arg::with_name(options::OS)
+            .short("o")
+            .long(options::OS)
+            .help("print the operating system name."))
+}
+
+
\ No newline at end of file diff --git a/src/uu_unexpand/unexpand.rs.html b/src/uu_unexpand/unexpand.rs.html new file mode 100644 index 000000000..63808b56e --- /dev/null +++ b/src/uu_unexpand/unexpand.rs.html @@ -0,0 +1,693 @@ +unexpand.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Virgile Andreani <virgile.andreani@anbuco.fr>
+//  * (c) kwantam <kwantam@gmail.com>
+//  *     * 2015-04-28 ~ updated to work with both UTF-8 and non-UTF-8 encodings
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) nums aflag uflag scol prevtab amode ctype cwidth nbytes lastcol pctype
+
+#[macro_use]
+extern crate uucore;
+use clap::{crate_version, App, Arg};
+use std::fs::File;
+use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Stdout, Write};
+use std::str::from_utf8;
+use unicode_width::UnicodeWidthChar;
+use uucore::InvalidEncodingHandling;
+
+static NAME: &str = "unexpand";
+static USAGE: &str = "unexpand [OPTION]... [FILE]...";
+static SUMMARY: &str = "Convert blanks in each FILE to tabs, writing to standard output.\n
+                 With no FILE, or when FILE is -, read standard input.";
+
+const DEFAULT_TABSTOP: usize = 8;
+
+fn tabstops_parse(s: String) -> Vec<usize> {
+    let words = s.split(',');
+
+    let nums = words
+        .map(|sn| {
+            sn.parse()
+                .unwrap_or_else(|_| crash!(1, "{}\n", "tab size contains invalid character(s)"))
+        })
+        .collect::<Vec<usize>>();
+
+    if nums.iter().any(|&n| n == 0) {
+        crash!(1, "{}\n", "tab size cannot be 0");
+    }
+
+    if let (false, _) = nums
+        .iter()
+        .fold((true, 0), |(acc, last), &n| (acc && last <= n, n))
+    {
+        crash!(1, "{}\n", "tab sizes must be ascending");
+    }
+
+    nums
+}
+
+mod options {
+    pub const FILE: &str = "file";
+    pub const ALL: &str = "all";
+    pub const FIRST_ONLY: &str = "first-only";
+    pub const TABS: &str = "tabs";
+    pub const NO_UTF8: &str = "no-utf8";
+}
+
+struct Options {
+    files: Vec<String>,
+    tabstops: Vec<usize>,
+    aflag: bool,
+    uflag: bool,
+}
+
+impl Options {
+    fn new(matches: clap::ArgMatches) -> Options {
+        let tabstops = match matches.value_of(options::TABS) {
+            None => vec![DEFAULT_TABSTOP],
+            Some(s) => tabstops_parse(s.to_string()),
+        };
+
+        let aflag = (matches.is_present(options::ALL) || matches.is_present(options::TABS))
+            && !matches.is_present(options::FIRST_ONLY);
+        let uflag = !matches.is_present(options::NO_UTF8);
+
+        let files = match matches.value_of(options::FILE) {
+            Some(v) => vec![v.to_string()],
+            None => vec!["-".to_owned()],
+        };
+
+        Options {
+            files,
+            tabstops,
+            aflag,
+            uflag,
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let matches = uu_app().get_matches_from(args);
+
+    unexpand(Options::new(matches));
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .name(NAME)
+        .version(crate_version!())
+        .usage(USAGE)
+        .about(SUMMARY)
+        .arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
+        .arg(
+            Arg::with_name(options::ALL)
+                .short("a")
+                .long(options::ALL)
+                .help("convert all blanks, instead of just initial blanks")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::FIRST_ONLY)
+                .long(options::FIRST_ONLY)
+                .help("convert only leading sequences of blanks (overrides -a)")
+                .takes_value(false),
+        )
+        .arg(
+            Arg::with_name(options::TABS)
+                .short("t")
+                .long(options::TABS)
+                .long_help("use comma separated LIST of tab positions or have tabs N characters apart instead of 8 (enables -a)")
+                .takes_value(true)
+        )
+        .arg(
+            Arg::with_name(options::NO_UTF8)
+                .short("U")
+                .long(options::NO_UTF8)
+                .takes_value(false)
+                .help("interpret input file as 8-bit ASCII rather than UTF-8"))
+}
+
+fn open(path: String) -> BufReader<Box<dyn Read + 'static>> {
+    let file_buf;
+    if path == "-" {
+        BufReader::new(Box::new(stdin()) as Box<dyn Read>)
+    } else {
+        file_buf = match File::open(&path[..]) {
+            Ok(a) => a,
+            Err(e) => crash!(1, "{}: {}", &path[..], e),
+        };
+        BufReader::new(Box::new(file_buf) as Box<dyn Read>)
+    }
+}
+
+fn next_tabstop(tabstops: &[usize], col: usize) -> Option<usize> {
+    if tabstops.len() == 1 {
+        Some(tabstops[0] - col % tabstops[0])
+    } else {
+        // find next larger tab
+        // if there isn't one in the list, tab becomes a single space
+        tabstops.iter().find(|&&t| t > col).map(|t| t - col)
+    }
+}
+
+fn write_tabs(
+    output: &mut BufWriter<Stdout>,
+    tabstops: &[usize],
+    mut scol: usize,
+    col: usize,
+    prevtab: bool,
+    init: bool,
+    amode: bool,
+) {
+    // This conditional establishes the following:
+    // We never turn a single space before a non-blank into
+    // a tab, unless it's at the start of the line.
+    let ai = init || amode;
+    if (ai && !prevtab && col > scol + 1) || (col > scol && (init || ai && prevtab)) {
+        while let Some(nts) = next_tabstop(tabstops, scol) {
+            if col < scol + nts {
+                break;
+            }
+
+            safe_unwrap!(output.write_all(b"\t"));
+            scol += nts;
+        }
+    }
+
+    while col > scol {
+        safe_unwrap!(output.write_all(b" "));
+        scol += 1;
+    }
+}
+
+#[derive(PartialEq, Eq, Debug)]
+enum CharType {
+    Backspace,
+    Space,
+    Tab,
+    Other,
+}
+
+fn next_char_info(uflag: bool, buf: &[u8], byte: usize) -> (CharType, usize, usize) {
+    let (ctype, cwidth, nbytes) = if uflag {
+        let nbytes = char::from(buf[byte]).len_utf8();
+
+        if byte + nbytes > buf.len() {
+            // make sure we don't overrun the buffer because of invalid UTF-8
+            (CharType::Other, 1, 1)
+        } else if let Ok(t) = from_utf8(&buf[byte..byte + nbytes]) {
+            // Now that we think it's UTF-8, figure out what kind of char it is
+            match t.chars().next() {
+                Some(' ') => (CharType::Space, 0, 1),
+                Some('\t') => (CharType::Tab, 0, 1),
+                Some('\x08') => (CharType::Backspace, 0, 1),
+                Some(c) => (
+                    CharType::Other,
+                    UnicodeWidthChar::width(c).unwrap_or(0),
+                    nbytes,
+                ),
+                None => {
+                    // invalid char snuck past the utf8_validation_iterator somehow???
+                    (CharType::Other, 1, 1)
+                }
+            }
+        } else {
+            // otherwise, it's not valid
+            (CharType::Other, 1, 1) // implicit assumption: non-UTF8 char has display width 1
+        }
+    } else {
+        (
+            match buf[byte] {
+                // always take exactly 1 byte in strict ASCII mode
+                0x20 => CharType::Space,
+                0x09 => CharType::Tab,
+                0x08 => CharType::Backspace,
+                _ => CharType::Other,
+            },
+            1,
+            1,
+        )
+    };
+
+    (ctype, cwidth, nbytes)
+}
+
+fn unexpand(options: Options) {
+    let mut output = BufWriter::new(stdout());
+    let ts = &options.tabstops[..];
+    let mut buf = Vec::new();
+    let lastcol = if ts.len() > 1 { *ts.last().unwrap() } else { 0 };
+
+    for file in options.files.into_iter() {
+        let mut fh = open(file);
+
+        while match fh.read_until(b'\n', &mut buf) {
+            Ok(s) => s > 0,
+            Err(_) => !buf.is_empty(),
+        } {
+            let mut byte = 0; // offset into the buffer
+            let mut col = 0; // the current column
+            let mut scol = 0; // the start col for the current span, i.e., the already-printed width
+            let mut init = true; // are we at the start of the line?
+            let mut pctype = CharType::Other;
+
+            while byte < buf.len() {
+                // when we have a finite number of columns, never convert past the last column
+                if lastcol > 0 && col >= lastcol {
+                    write_tabs(
+                        &mut output,
+                        ts,
+                        scol,
+                        col,
+                        pctype == CharType::Tab,
+                        init,
+                        true,
+                    );
+                    safe_unwrap!(output.write_all(&buf[byte..]));
+                    scol = col;
+                    break;
+                }
+
+                // figure out how big the next char is, if it's UTF-8
+                let (ctype, cwidth, nbytes) = next_char_info(options.uflag, &buf, byte);
+
+                // now figure out how many columns this char takes up, and maybe print it
+                let tabs_buffered = init || options.aflag;
+                match ctype {
+                    CharType::Space | CharType::Tab => {
+                        // compute next col, but only write space or tab chars if not buffering
+                        col += if ctype == CharType::Space {
+                            1
+                        } else {
+                            next_tabstop(ts, col).unwrap_or(1)
+                        };
+
+                        if !tabs_buffered {
+                            safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
+                            scol = col; // now printed up to this column
+                        }
+                    }
+                    CharType::Other | CharType::Backspace => {
+                        // always
+                        write_tabs(
+                            &mut output,
+                            ts,
+                            scol,
+                            col,
+                            pctype == CharType::Tab,
+                            init,
+                            options.aflag,
+                        );
+                        init = false; // no longer at the start of a line
+                        col = if ctype == CharType::Other {
+                            // use computed width
+                            col + cwidth
+                        } else if col > 0 {
+                            // Backspace case, but only if col > 0
+                            col - 1
+                        } else {
+                            0
+                        };
+                        safe_unwrap!(output.write_all(&buf[byte..byte + nbytes]));
+                        scol = col; // we've now printed up to this column
+                    }
+                }
+
+                byte += nbytes; // move on to next char
+                pctype = ctype; // save the previous type
+            }
+
+            // write out anything remaining
+            write_tabs(
+                &mut output,
+                ts,
+                scol,
+                col,
+                pctype == CharType::Tab,
+                init,
+                true,
+            );
+            safe_unwrap!(output.flush());
+            buf.truncate(0); // clear out the buffer
+        }
+    }
+    crash_if_err!(1, output.flush())
+}
+
+
\ No newline at end of file diff --git a/src/uu_uniq/uniq.rs.html b/src/uu_uniq/uniq.rs.html new file mode 100644 index 000000000..a7c0dffab --- /dev/null +++ b/src/uu_uniq/uniq.rs.html @@ -0,0 +1,831 @@ +uniq.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Chirag B Jadwani <chirag.jadwani@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use std::fs::File;
+use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write};
+use std::path::Path;
+use std::str::FromStr;
+use strum_macros::{AsRefStr, EnumString};
+
+static ABOUT: &str = "Report or omit repeated lines.";
+pub mod options {
+    pub static ALL_REPEATED: &str = "all-repeated";
+    pub static CHECK_CHARS: &str = "check-chars";
+    pub static COUNT: &str = "count";
+    pub static IGNORE_CASE: &str = "ignore-case";
+    pub static REPEATED: &str = "repeated";
+    pub static SKIP_FIELDS: &str = "skip-fields";
+    pub static SKIP_CHARS: &str = "skip-chars";
+    pub static UNIQUE: &str = "unique";
+    pub static ZERO_TERMINATED: &str = "zero-terminated";
+    pub static GROUP: &str = "group";
+}
+
+static ARG_FILES: &str = "files";
+
+#[derive(PartialEq, Clone, Copy, AsRefStr, EnumString)]
+#[strum(serialize_all = "snake_case")]
+enum Delimiters {
+    Append,
+    Prepend,
+    Separate,
+    Both,
+    None,
+}
+
+struct Uniq {
+    repeats_only: bool,
+    uniques_only: bool,
+    all_repeated: bool,
+    delimiters: Delimiters,
+    show_counts: bool,
+    skip_fields: Option<usize>,
+    slice_start: Option<usize>,
+    slice_stop: Option<usize>,
+    ignore_case: bool,
+    zero_terminated: bool,
+}
+
+impl Uniq {
+    pub fn print_uniq<R: Read, W: Write>(
+        &self,
+        reader: &mut BufReader<R>,
+        writer: &mut BufWriter<W>,
+    ) {
+        let mut first_line_printed = false;
+        let mut group_count = 1;
+        let line_terminator = self.get_line_terminator();
+        let mut lines = reader.split(line_terminator).map(get_line_string);
+        let mut line = match lines.next() {
+            Some(l) => l,
+            None => return,
+        };
+
+        // compare current `line` with consecutive lines (`next_line`) of the input
+        // and if needed, print `line` based on the command line options provided
+        for next_line in lines {
+            if self.cmp_keys(&line, &next_line) {
+                if (group_count == 1 && !self.repeats_only)
+                    || (group_count > 1 && !self.uniques_only)
+                {
+                    self.print_line(writer, &line, group_count, first_line_printed);
+                    first_line_printed = true;
+                }
+                line = next_line;
+                group_count = 1;
+            } else {
+                if self.all_repeated {
+                    self.print_line(writer, &line, group_count, first_line_printed);
+                    first_line_printed = true;
+                    line = next_line;
+                }
+                group_count += 1;
+            }
+        }
+        if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
+            self.print_line(writer, &line, group_count, first_line_printed);
+            first_line_printed = true;
+        }
+        if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
+            && first_line_printed
+        {
+            crash_if_err!(1, writer.write_all(&[line_terminator]));
+        }
+    }
+
+    fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
+        if let Some(skip_fields) = self.skip_fields {
+            let mut i = 0;
+            let mut char_indices = line.char_indices();
+            for _ in 0..skip_fields {
+                if char_indices.find(|(_, c)| !c.is_whitespace()) == None {
+                    return "";
+                }
+                match char_indices.find(|(_, c)| c.is_whitespace()) {
+                    None => return "",
+
+                    Some((next_field_i, _)) => i = next_field_i,
+                }
+            }
+            &line[i..]
+        } else {
+            line
+        }
+    }
+
+    fn get_line_terminator(&self) -> u8 {
+        if self.zero_terminated {
+            0
+        } else {
+            b'\n'
+        }
+    }
+
+    fn cmp_keys(&self, first: &str, second: &str) -> bool {
+        self.cmp_key(first, |first_iter| {
+            self.cmp_key(second, |second_iter| first_iter.ne(second_iter))
+        })
+    }
+
+    fn cmp_key<F>(&self, line: &str, mut closure: F) -> bool
+    where
+        F: FnMut(&mut dyn Iterator<Item = char>) -> bool,
+    {
+        let fields_to_check = self.skip_fields(line);
+        let len = fields_to_check.len();
+        let slice_start = self.slice_start.unwrap_or(0);
+        let slice_stop = self.slice_stop.unwrap_or(len);
+        if len > 0 {
+            // fast path: avoid doing any work if there is no need to skip or map to lower-case
+            if !self.ignore_case && slice_start == 0 && slice_stop == len {
+                return closure(&mut fields_to_check.chars());
+            }
+
+            // fast path: avoid skipping
+            if self.ignore_case && slice_start == 0 && slice_stop == len {
+                return closure(&mut fields_to_check.chars().flat_map(|c| c.to_uppercase()));
+            }
+
+            // fast path: we can avoid mapping chars to upper-case, if we don't want to ignore the case
+            if !self.ignore_case {
+                return closure(&mut fields_to_check.chars().skip(slice_start).take(slice_stop));
+            }
+
+            closure(
+                &mut fields_to_check
+                    .chars()
+                    .skip(slice_start)
+                    .take(slice_stop)
+                    .flat_map(|c| c.to_uppercase()),
+            )
+        } else {
+            closure(&mut fields_to_check.chars())
+        }
+    }
+
+    fn should_print_delimiter(&self, group_count: usize, first_line_printed: bool) -> bool {
+        // if no delimiter option is selected then no other checks needed
+        self.delimiters != Delimiters::None
+            // print delimiter only before the first line of a group, not between lines of a group
+            && group_count == 1
+            // if at least one line has been output before current group then print delimiter
+            && (first_line_printed
+                // or if we need to prepend delimiter then print it even at the start of the output
+                || self.delimiters == Delimiters::Prepend
+                // the 'both' delimit mode should prepend and append delimiters
+                || self.delimiters == Delimiters::Both)
+    }
+
+    fn print_line<W: Write>(
+        &self,
+        writer: &mut BufWriter<W>,
+        line: &str,
+        count: usize,
+        first_line_printed: bool,
+    ) {
+        let line_terminator = self.get_line_terminator();
+
+        if self.should_print_delimiter(count, first_line_printed) {
+            crash_if_err!(1, writer.write_all(&[line_terminator]));
+        }
+
+        crash_if_err!(
+            1,
+            if self.show_counts {
+                writer.write_all(format!("{:7} {}", count, line).as_bytes())
+            } else {
+                writer.write_all(line.as_bytes())
+            }
+        );
+        crash_if_err!(1, writer.write_all(&[line_terminator]));
+    }
+}
+
+fn get_line_string(io_line: Result<Vec<u8>>) -> String {
+    let line_bytes = crash_if_err!(1, io_line);
+    crash_if_err!(1, String::from_utf8(line_bytes))
+}
+
+fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> {
+    matches.value_of(opt_name).map(|arg_str| {
+        let opt_val: Option<T> = arg_str.parse().ok();
+        opt_val.unwrap_or_else(|| crash!(1, "Invalid argument for {}: {}", opt_name, arg_str))
+    })
+}
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [INPUT [OUTPUT]]...",
+        uucore::execution_phrase()
+    )
+}
+
+fn get_long_usage() -> String {
+    String::from(
+        "Filter adjacent matching lines from INPUT (or standard input),\n\
+        writing to OUTPUT (or standard output).
+        Note: 'uniq' does not detect repeated lines unless they are adjacent.\n\
+        You may want to sort the input first, or use 'sort -u' without 'uniq'.\n",
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let long_usage = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&long_usage[..])
+        .get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let (in_file_name, out_file_name) = match files.len() {
+        0 => ("-".to_owned(), "-".to_owned()),
+        1 => (files[0].clone(), "-".to_owned()),
+        2 => (files[0].clone(), files[1].clone()),
+        _ => {
+            // Cannot happen as clap will fail earlier
+            crash!(1, "Extra operand: {}", files[2]);
+        }
+    };
+
+    let uniq = Uniq {
+        repeats_only: matches.is_present(options::REPEATED)
+            || matches.is_present(options::ALL_REPEATED),
+        uniques_only: matches.is_present(options::UNIQUE),
+        all_repeated: matches.is_present(options::ALL_REPEATED)
+            || matches.is_present(options::GROUP),
+        delimiters: get_delimiter(&matches),
+        show_counts: matches.is_present(options::COUNT),
+        skip_fields: opt_parsed(options::SKIP_FIELDS, &matches),
+        slice_start: opt_parsed(options::SKIP_CHARS, &matches),
+        slice_stop: opt_parsed(options::CHECK_CHARS, &matches),
+        ignore_case: matches.is_present(options::IGNORE_CASE),
+        zero_terminated: matches.is_present(options::ZERO_TERMINATED),
+    };
+    uniq.print_uniq(
+        &mut open_input_file(in_file_name),
+        &mut open_output_file(out_file_name),
+    );
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::ALL_REPEATED)
+                .short("D")
+                .long(options::ALL_REPEATED)
+                .possible_values(&[
+                    Delimiters::None.as_ref(), Delimiters::Prepend.as_ref(), Delimiters::Separate.as_ref()
+                ])
+                .help("print all duplicate lines. Delimiting is done with blank lines. [default: none]")
+                .value_name("delimit-method")
+                .min_values(0)
+                .max_values(1),
+        )
+        .arg(
+            Arg::with_name(options::GROUP)
+                .long(options::GROUP)
+                .possible_values(&[
+                    Delimiters::Separate.as_ref(), Delimiters::Prepend.as_ref(),
+                    Delimiters::Append.as_ref(), Delimiters::Both.as_ref()
+                ])
+                .help("show all items, separating groups with an empty line. [default: separate]")
+                .value_name("group-method")
+                .min_values(0)
+                .max_values(1)
+                .conflicts_with_all(&[
+                    options::REPEATED,
+                    options::ALL_REPEATED,
+                    options::UNIQUE,
+                ]),
+        )
+        .arg(
+            Arg::with_name(options::CHECK_CHARS)
+                .short("w")
+                .long(options::CHECK_CHARS)
+                .help("compare no more than N characters in lines")
+                .value_name("N"),
+        )
+        .arg(
+            Arg::with_name(options::COUNT)
+                .short("c")
+                .long(options::COUNT)
+                .help("prefix lines by the number of occurrences"),
+        )
+        .arg(
+            Arg::with_name(options::IGNORE_CASE)
+                .short("i")
+                .long(options::IGNORE_CASE)
+                .help("ignore differences in case when comparing"),
+        )
+        .arg(
+            Arg::with_name(options::REPEATED)
+                .short("d")
+                .long(options::REPEATED)
+                .help("only print duplicate lines"),
+        )
+        .arg(
+            Arg::with_name(options::SKIP_CHARS)
+                .short("s")
+                .long(options::SKIP_CHARS)
+                .help("avoid comparing the first N characters")
+                .value_name("N"),
+        )
+        .arg(
+            Arg::with_name(options::SKIP_FIELDS)
+                .short("f")
+                .long(options::SKIP_FIELDS)
+                .help("avoid comparing the first N fields")
+                .value_name("N"),
+        )
+        .arg(
+            Arg::with_name(options::UNIQUE)
+                .short("u")
+                .long(options::UNIQUE)
+                .help("only print unique lines"),
+        )
+        .arg(
+            Arg::with_name(options::ZERO_TERMINATED)
+                .short("z")
+                .long(options::ZERO_TERMINATED)
+                .help("end lines with 0 byte, not newline"),
+        )
+        .arg(
+            Arg::with_name(ARG_FILES)
+                .multiple(true)
+                .takes_value(true)
+                .max_values(2),
+        )
+}
+
+fn get_delimiter(matches: &ArgMatches) -> Delimiters {
+    let value = matches
+        .value_of(options::ALL_REPEATED)
+        .or_else(|| matches.value_of(options::GROUP));
+    if let Some(delimiter_arg) = value {
+        crash_if_err!(1, Delimiters::from_str(delimiter_arg))
+    } else if matches.is_present(options::GROUP) {
+        Delimiters::Separate
+    } else {
+        Delimiters::None
+    }
+}
+
+fn open_input_file(in_file_name: String) -> BufReader<Box<dyn Read + 'static>> {
+    let in_file = if in_file_name == "-" {
+        Box::new(stdin()) as Box<dyn Read>
+    } else {
+        let path = Path::new(&in_file_name[..]);
+        let in_file = File::open(&path);
+        let r = crash_if_err!(1, in_file);
+        Box::new(r) as Box<dyn Read>
+    };
+    BufReader::new(in_file)
+}
+
+fn open_output_file(out_file_name: String) -> BufWriter<Box<dyn Write + 'static>> {
+    let out_file = if out_file_name == "-" {
+        Box::new(stdout()) as Box<dyn Write>
+    } else {
+        let path = Path::new(&out_file_name[..]);
+        let in_file = File::create(&path);
+        let w = crash_if_err!(1, in_file);
+        Box::new(w) as Box<dyn Write>
+    };
+    BufWriter::new(out_file)
+}
+
+
\ No newline at end of file diff --git a/src/uu_unlink/unlink.rs.html b/src/uu_unlink/unlink.rs.html new file mode 100644 index 000000000..e50a9c61f --- /dev/null +++ b/src/uu_unlink/unlink.rs.html @@ -0,0 +1,209 @@ +unlink.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Colin Warren <me@zv.ms>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+/* last synced with: unlink (GNU coreutils) 8.21 */
+
+// spell-checker:ignore (ToDO) lstat IFLNK IFMT IFREG
+
+#[macro_use]
+extern crate uucore;
+
+use clap::{crate_version, App, Arg};
+use libc::{lstat, stat, unlink};
+use libc::{S_IFLNK, S_IFMT, S_IFREG};
+use std::ffi::CString;
+use std::io::{Error, ErrorKind};
+use uucore::InvalidEncodingHandling;
+
+static ABOUT: &str = "Unlink the file at [FILE].";
+static OPT_PATH: &str = "FILE";
+
+fn usage() -> String {
+    format!("{} [OPTION]... FILE", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::ConvertLossy)
+        .accept_any();
+
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let paths: Vec<String> = matches
+        .values_of(OPT_PATH)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    if paths.is_empty() {
+        crash!(
+            1,
+            "missing operand\nTry '{0} --help' for more information.",
+            uucore::execution_phrase()
+        );
+    } else if paths.len() > 1 {
+        crash!(
+            1,
+            "extra operand: '{1}'\nTry '{0} --help' for more information.",
+            uucore::execution_phrase(),
+            paths[1]
+        );
+    }
+
+    let c_string = CString::new(paths[0].clone()).unwrap(); // unwrap() cannot fail, the string comes from argv so it cannot contain a \0.
+
+    let st_mode = {
+        #[allow(deprecated)]
+        let mut buf: stat = unsafe { std::mem::uninitialized() };
+        let result = unsafe { lstat(c_string.as_ptr(), &mut buf as *mut stat) };
+
+        if result < 0 {
+            crash!(1, "Cannot stat '{}': {}", paths[0], Error::last_os_error());
+        }
+
+        buf.st_mode & S_IFMT
+    };
+
+    let result = if st_mode != S_IFREG && st_mode != S_IFLNK {
+        Err(Error::new(
+            ErrorKind::Other,
+            "Not a regular file or symlink",
+        ))
+    } else {
+        let result = unsafe { unlink(c_string.as_ptr()) };
+
+        if result < 0 {
+            Err(Error::last_os_error())
+        } else {
+            Ok(())
+        }
+    };
+
+    match result {
+        Ok(_) => (),
+        Err(e) => {
+            crash!(1, "cannot unlink '{0}': {1}", paths[0], e);
+        }
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(Arg::with_name(OPT_PATH).hidden(true).multiple(true))
+}
+
+
\ No newline at end of file diff --git a/src/uu_uptime/uptime.rs.html b/src/uu_uptime/uptime.rs.html new file mode 100644 index 000000000..46b56d84c --- /dev/null +++ b/src/uu_uptime/uptime.rs.html @@ -0,0 +1,375 @@ +uptime.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  * (c) Jian Zeng <anonymousknight86@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) getloadavg upsecs updays nusers loadavg boottime uphours upmins
+
+use chrono::{Local, TimeZone, Utc};
+use clap::{crate_version, App, Arg};
+
+#[macro_use]
+extern crate uucore;
+// import crate time from utmpx
+pub use uucore::libc;
+use uucore::libc::time_t;
+
+static ABOUT: &str = "Display the current time, the length of time the system has been up,\n\
+                      the number of users on the system, and the average number of jobs\n\
+                      in the run queue over the last 1, 5 and 15 minutes.";
+pub mod options {
+    pub static SINCE: &str = "since";
+}
+
+#[cfg(unix)]
+use uucore::libc::getloadavg;
+
+#[cfg(windows)]
+extern "C" {
+    fn GetTickCount() -> uucore::libc::uint32_t;
+}
+
+fn usage() -> String {
+    format!("{0} [OPTION]...", uucore::execution_phrase())
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let (boot_time, user_count) = process_utmpx();
+    let uptime = get_uptime(boot_time);
+    if uptime < 0 {
+        show_error!("could not retrieve system uptime");
+
+        1
+    } else {
+        if matches.is_present(options::SINCE) {
+            let initial_date = Local.timestamp(Utc::now().timestamp() - uptime, 0);
+            println!("{}", initial_date.format("%Y-%m-%d %H:%M:%S"));
+            return 0;
+        }
+
+        print_time();
+        let upsecs = uptime;
+        print_uptime(upsecs);
+        print_nusers(user_count);
+        print_loadavg();
+
+        0
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::SINCE)
+                .short("s")
+                .long(options::SINCE)
+                .help("system up since"),
+        )
+}
+
+#[cfg(unix)]
+fn print_loadavg() {
+    use uucore::libc::c_double;
+
+    let mut avg: [c_double; 3] = [0.0; 3];
+    let loads: i32 = unsafe { getloadavg(avg.as_mut_ptr(), 3) };
+
+    if loads == -1 {
+        println!();
+    } else {
+        print!("load average: ");
+        for n in 0..loads {
+            print!(
+                "{:.2}{}",
+                avg[n as usize],
+                if n == loads - 1 { "\n" } else { ", " }
+            );
+        }
+    }
+}
+
+#[cfg(windows)]
+fn print_loadavg() {
+    // XXX: currently this is a noop as Windows does not seem to have anything comparable to
+    //      getloadavg()
+}
+
+#[cfg(unix)]
+fn process_utmpx() -> (Option<time_t>, usize) {
+    use uucore::utmpx::*;
+
+    let mut nusers = 0;
+    let mut boot_time = None;
+
+    for line in Utmpx::iter_all_records() {
+        match line.record_type() {
+            USER_PROCESS => nusers += 1,
+            BOOT_TIME => {
+                let t = line.login_time().to_timespec();
+                if t.sec > 0 {
+                    boot_time = Some(t.sec as time_t);
+                }
+            }
+            _ => continue,
+        }
+    }
+    (boot_time, nusers)
+}
+
+#[cfg(windows)]
+fn process_utmpx() -> (Option<time_t>, usize) {
+    (None, 0) // TODO: change 0 to number of users
+}
+
+fn print_nusers(nusers: usize) {
+    match nusers.cmp(&1) {
+        std::cmp::Ordering::Equal => print!("1 user,  "),
+        std::cmp::Ordering::Greater => print!("{} users,  ", nusers),
+        _ => {}
+    };
+}
+
+fn print_time() {
+    let local_time = Local::now().time();
+
+    print!(" {} ", local_time.format("%H:%M:%S"));
+}
+
+#[cfg(unix)]
+fn get_uptime(boot_time: Option<time_t>) -> i64 {
+    use std::fs::File;
+    use std::io::Read;
+
+    let mut proc_uptime_s = String::new();
+
+    let proc_uptime = File::open("/proc/uptime")
+        .ok()
+        .and_then(|mut f| f.read_to_string(&mut proc_uptime_s).ok())
+        .and_then(|_| proc_uptime_s.split_whitespace().next())
+        .and_then(|s| s.split('.').next().unwrap_or("0").parse().ok());
+
+    proc_uptime.unwrap_or_else(|| match boot_time {
+        Some(t) => {
+            let now = Local::now().timestamp();
+            let boottime = t as i64;
+            now - boottime
+        }
+        None => -1,
+    })
+}
+
+#[cfg(windows)]
+fn get_uptime(_boot_time: Option<time_t>) -> i64 {
+    unsafe { GetTickCount() as i64 }
+}
+
+fn print_uptime(upsecs: i64) {
+    let updays = upsecs / 86400;
+    let uphours = (upsecs - (updays * 86400)) / 3600;
+    let upmins = (upsecs - (updays * 86400) - (uphours * 3600)) / 60;
+    match updays.cmp(&1) {
+        std::cmp::Ordering::Equal => print!("up {:1} day, {:2}:{:02},  ", updays, uphours, upmins),
+        std::cmp::Ordering::Greater => {
+            print!("up {:1} days, {:2}:{:02},  ", updays, uphours, upmins)
+        }
+        _ => print!("up  {:2}:{:02}, ", uphours, upmins),
+    };
+}
+
+
\ No newline at end of file diff --git a/src/uu_users/users.rs.html b/src/uu_users/users.rs.html new file mode 100644 index 000000000..286cd9866 --- /dev/null +++ b/src/uu_users/users.rs.html @@ -0,0 +1,143 @@ +users.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) KokaKiwi <kokakiwi@kokakiwi.net>
+//  * (c) Jian Zeng <anonymousknight86@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (paths) wtmp
+
+use clap::{crate_version, App, Arg};
+use uucore::utmpx::{self, Utmpx};
+
+static ABOUT: &str = "Print the user names of users currently logged in to the current host";
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!("{0} [FILE]", uucore::execution_phrase())
+}
+
+fn get_long_usage() -> String {
+    format!(
+        "Output who is currently logged in according to FILE.
+If FILE is not specified, use {}.  /var/log/wtmp as FILE is common.",
+        utmpx::DEFAULT_FILE
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+    let after_help = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(ARG_FILES)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    let filename = if !files.is_empty() {
+        files[0].as_ref()
+    } else {
+        utmpx::DEFAULT_FILE
+    };
+
+    let mut users = Utmpx::iter_all_records()
+        .read_from(filename)
+        .filter(Utmpx::is_user_process)
+        .map(|ut| ut.user())
+        .collect::<Vec<_>>();
+
+    if !users.is_empty() {
+        users.sort();
+        println!("{}", users.join(" "));
+    }
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(Arg::with_name(ARG_FILES).takes_value(true).max_values(1))
+}
+
+
\ No newline at end of file diff --git a/src/uu_wc/count_bytes.rs.html b/src/uu_wc/count_bytes.rs.html new file mode 100644 index 000000000..2d7aa37eb --- /dev/null +++ b/src/uu_wc/count_bytes.rs.html @@ -0,0 +1,227 @@ +count_bytes.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+
+use super::{WcResult, WordCountable};
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use std::fs::{File, OpenOptions};
+use std::io::ErrorKind;
+
+#[cfg(unix)]
+use libc::S_IFREG;
+#[cfg(unix)]
+use nix::sys::stat::fstat;
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use libc::S_IFIFO;
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use nix::fcntl::{splice, SpliceFFlags};
+#[cfg(any(target_os = "linux", target_os = "android"))]
+use nix::unistd::pipe;
+
+const BUF_SIZE: usize = 16384;
+
+/// Splice wrapper which handles short writes
+#[cfg(any(target_os = "linux", target_os = "android"))]
+#[inline]
+fn splice_exact(read_fd: RawFd, write_fd: RawFd, num_bytes: usize) -> nix::Result<()> {
+    let mut left = num_bytes;
+    loop {
+        let written = splice(read_fd, None, write_fd, None, left, SpliceFFlags::empty())?;
+        left -= written;
+        if left == 0 {
+            break;
+        }
+    }
+    Ok(())
+}
+
+/// This is a Linux-specific function to count the number of bytes using the
+/// `splice` system call, which is faster than using `read`.
+#[inline]
+#[cfg(any(target_os = "linux", target_os = "android"))]
+fn count_bytes_using_splice(fd: RawFd) -> nix::Result<usize> {
+    let null_file = OpenOptions::new()
+        .write(true)
+        .open("/dev/null")
+        .map_err(|_| nix::Error::last())?;
+    let null = null_file.as_raw_fd();
+    let (pipe_rd, pipe_wr) = pipe()?;
+
+    // Ensure the pipe is closed when the function returns.
+    // SAFETY: The file descriptors do not have other owners.
+    let _handles = unsafe { (File::from_raw_fd(pipe_rd), File::from_raw_fd(pipe_wr)) };
+
+    let mut byte_count = 0;
+    loop {
+        let res = splice(fd, None, pipe_wr, None, BUF_SIZE, SpliceFFlags::empty())?;
+        if res == 0 {
+            break;
+        }
+        byte_count += res;
+        splice_exact(pipe_rd, null, res)?;
+    }
+
+    Ok(byte_count)
+}
+
+/// In the special case where we only need to count the number of bytes. There
+/// are several optimizations we can do:
+///   1. On Unix,  we can simply `stat` the file if it is regular.
+///   2. On Linux -- if the above did not work -- we can use splice to count
+///      the number of bytes if the file is a FIFO.
+///   3. Otherwise, we just read normally, but without the overhead of counting
+///      other things such as lines and words.
+#[inline]
+pub(crate) fn count_bytes_fast<T: WordCountable>(handle: &mut T) -> WcResult<usize> {
+    #[cfg(unix)]
+    {
+        let fd = handle.as_raw_fd();
+        if let Ok(stat) = fstat(fd) {
+            // If the file is regular, then the `st_size` should hold
+            // the file's size in bytes.
+            if (stat.st_mode & S_IFREG) != 0 {
+                return Ok(stat.st_size as usize);
+            }
+            #[cfg(any(target_os = "linux", target_os = "android"))]
+            {
+                // Else, if we're on Linux and our file is a FIFO pipe
+                // (or stdin), we use splice to count the number of bytes.
+                if (stat.st_mode & S_IFIFO) != 0 {
+                    if let Ok(n) = count_bytes_using_splice(fd) {
+                        return Ok(n);
+                    }
+                }
+            }
+        }
+    }
+
+    // Fall back on `read`, but without the overhead of counting words and lines.
+    let mut buf = [0_u8; BUF_SIZE];
+    let mut byte_count = 0;
+    loop {
+        match handle.read(&mut buf) {
+            Ok(0) => return Ok(byte_count),
+            Ok(n) => {
+                byte_count += n;
+            }
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+            Err(e) => return Err(e.into()),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_wc/countable.rs.html b/src/uu_wc/countable.rs.html new file mode 100644 index 000000000..2cf069dde --- /dev/null +++ b/src/uu_wc/countable.rs.html @@ -0,0 +1,149 @@ +countable.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+
+//! Traits and implementations for iterating over lines in a file-like object.
+//!
+//! This module provides a [`WordCountable`] trait and implementations
+//! for some common file-like objects. Use the [`WordCountable::lines`]
+//! method to get an iterator over lines of a file-like object.
+use std::fs::File;
+use std::io::{self, BufRead, BufReader, Read, StdinLock};
+
+#[cfg(unix)]
+use std::os::unix::io::AsRawFd;
+
+#[cfg(unix)]
+pub trait WordCountable: AsRawFd + Read {
+    type Buffered: BufRead;
+    fn lines(self) -> Lines<Self::Buffered>;
+}
+
+#[cfg(not(unix))]
+pub trait WordCountable: Read {
+    type Buffered: BufRead;
+    fn lines(self) -> Lines<Self::Buffered>;
+}
+
+impl WordCountable for StdinLock<'_> {
+    type Buffered = Self;
+
+    fn lines(self) -> Lines<Self::Buffered>
+    where
+        Self: Sized,
+    {
+        Lines { buf: self }
+    }
+}
+impl WordCountable for File {
+    type Buffered = BufReader<Self>;
+
+    fn lines(self) -> Lines<Self::Buffered>
+    where
+        Self: Sized,
+    {
+        Lines {
+            buf: BufReader::new(self),
+        }
+    }
+}
+
+/// An iterator over the lines of an instance of `BufRead`.
+///
+/// Similar to [`io::Lines`] but yields each line as a `Vec<u8>` and
+/// includes the newline character (`\n`, the `0xA` byte) that
+/// terminates the line.
+///
+/// [`io::Lines`]:: io::Lines
+pub struct Lines<B> {
+    buf: B,
+}
+
+impl<B: BufRead> Iterator for Lines<B> {
+    type Item = io::Result<Vec<u8>>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let mut line = Vec::new();
+
+        // reading from a TTY seems to raise a condition on, rather than return Some(0) like a file.
+        // hence the option wrapped in a result here
+        match self.buf.read_until(b'\n', &mut line) {
+            Ok(0) => None,
+            Ok(_n) => Some(Ok(line)),
+            Err(e) => Some(Err(e)),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_wc/wc.rs.html b/src/uu_wc/wc.rs.html new file mode 100644 index 000000000..2651af236 --- /dev/null +++ b/src/uu_wc/wc.rs.html @@ -0,0 +1,941 @@ +wc.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Boden Garman <bpgarman@gmail.com>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+#[macro_use]
+extern crate uucore;
+
+mod count_bytes;
+mod countable;
+mod word_count;
+use count_bytes::count_bytes_fast;
+use countable::WordCountable;
+use word_count::{TitledWordCount, WordCount};
+
+use clap::{crate_version, App, Arg, ArgMatches};
+use thiserror::Error;
+
+use std::fs::{self, File};
+use std::io::{self, ErrorKind, Write};
+use std::path::Path;
+
+/// The minimum character width for formatting counts when reading from stdin.
+const MINIMUM_WIDTH: usize = 7;
+
+#[derive(Error, Debug)]
+pub enum WcError {
+    #[error("{0}")]
+    Io(#[from] io::Error),
+    #[error("Expected a file, found directory {0}")]
+    IsDirectory(String),
+}
+
+type WcResult<T> = Result<T, WcError>;
+
+struct Settings {
+    show_bytes: bool,
+    show_chars: bool,
+    show_lines: bool,
+    show_words: bool,
+    show_max_line_length: bool,
+}
+
+impl Settings {
+    fn new(matches: &ArgMatches) -> Settings {
+        let settings = Settings {
+            show_bytes: matches.is_present(options::BYTES),
+            show_chars: matches.is_present(options::CHAR),
+            show_lines: matches.is_present(options::LINES),
+            show_words: matches.is_present(options::WORDS),
+            show_max_line_length: matches.is_present(options::MAX_LINE_LENGTH),
+        };
+
+        if settings.show_bytes
+            || settings.show_chars
+            || settings.show_lines
+            || settings.show_words
+            || settings.show_max_line_length
+        {
+            return settings;
+        }
+
+        Settings {
+            show_bytes: true,
+            show_chars: false,
+            show_lines: true,
+            show_words: true,
+            show_max_line_length: false,
+        }
+    }
+
+    fn number_enabled(&self) -> u32 {
+        let mut result = 0;
+        result += self.show_bytes as u32;
+        result += self.show_chars as u32;
+        result += self.show_lines as u32;
+        result += self.show_max_line_length as u32;
+        result += self.show_words as u32;
+        result
+    }
+}
+
+static ABOUT: &str = "Display newline, word, and byte counts for each FILE, and a total line if
+more than one FILE is specified.";
+
+pub mod options {
+    pub static BYTES: &str = "bytes";
+    pub static CHAR: &str = "chars";
+    pub static LINES: &str = "lines";
+    pub static MAX_LINE_LENGTH: &str = "max-line-length";
+    pub static WORDS: &str = "words";
+}
+
+static ARG_FILES: &str = "files";
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [FILE]...
+ With no FILE, or when FILE is -, read standard input.",
+        uucore::execution_phrase()
+    )
+}
+
+enum StdinKind {
+    /// Stdin specified on command-line with "-".
+    Explicit,
+
+    /// Stdin implicitly specified on command-line by not passing any positional argument.
+    Implicit,
+}
+
+/// Supported inputs.
+enum Input {
+    /// A regular file.
+    Path(String),
+
+    /// Standard input.
+    Stdin(StdinKind),
+}
+
+impl Input {
+    /// Converts input to title that appears in stats.
+    fn to_title(&self) -> Option<&str> {
+        match self {
+            Input::Path(path) => Some(path),
+            Input::Stdin(StdinKind::Explicit) => Some("-"),
+            Input::Stdin(StdinKind::Implicit) => None,
+        }
+    }
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let usage = usage();
+
+    let matches = uu_app().usage(&usage[..]).get_matches_from(args);
+
+    let mut inputs: Vec<Input> = matches
+        .values_of(ARG_FILES)
+        .map(|v| {
+            v.map(|i| {
+                if i == "-" {
+                    Input::Stdin(StdinKind::Explicit)
+                } else {
+                    Input::Path(ToString::to_string(i))
+                }
+            })
+            .collect()
+        })
+        .unwrap_or_default();
+
+    if inputs.is_empty() {
+        inputs.push(Input::Stdin(StdinKind::Implicit));
+    }
+
+    let settings = Settings::new(&matches);
+
+    if wc(inputs, &settings).is_ok() {
+        0
+    } else {
+        1
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::BYTES)
+                .short("c")
+                .long(options::BYTES)
+                .help("print the byte counts"),
+        )
+        .arg(
+            Arg::with_name(options::CHAR)
+                .short("m")
+                .long(options::CHAR)
+                .help("print the character counts"),
+        )
+        .arg(
+            Arg::with_name(options::LINES)
+                .short("l")
+                .long(options::LINES)
+                .help("print the newline counts"),
+        )
+        .arg(
+            Arg::with_name(options::MAX_LINE_LENGTH)
+                .short("L")
+                .long(options::MAX_LINE_LENGTH)
+                .help("print the length of the longest line"),
+        )
+        .arg(
+            Arg::with_name(options::WORDS)
+                .short("w")
+                .long(options::WORDS)
+                .help("print the word counts"),
+        )
+        .arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
+}
+
+fn word_count_from_reader<T: WordCountable>(
+    mut reader: T,
+    settings: &Settings,
+    path: &str,
+) -> WcResult<WordCount> {
+    let only_count_bytes = settings.show_bytes
+        && (!(settings.show_chars
+            || settings.show_lines
+            || settings.show_max_line_length
+            || settings.show_words));
+    if only_count_bytes {
+        return Ok(WordCount {
+            bytes: count_bytes_fast(&mut reader)?,
+            ..WordCount::default()
+        });
+    }
+
+    // we do not need to decode the byte stream if we're only counting bytes/newlines
+    let decode_chars = settings.show_chars || settings.show_words || settings.show_max_line_length;
+
+    // Sum the WordCount for each line. Show a warning for each line
+    // that results in an IO error when trying to read it.
+    let total = reader
+        .lines()
+        .filter_map(|res| match res {
+            Ok(line) => Some(line),
+            Err(e) => {
+                show_warning!("Error while reading {}: {}", path, e);
+                None
+            }
+        })
+        .map(|line| WordCount::from_line(&line, decode_chars))
+        .sum();
+    Ok(total)
+}
+
+fn word_count_from_input(input: &Input, settings: &Settings) -> WcResult<WordCount> {
+    match input {
+        Input::Stdin(_) => {
+            let stdin = io::stdin();
+            let stdin_lock = stdin.lock();
+            word_count_from_reader(stdin_lock, settings, "-")
+        }
+        Input::Path(path) => {
+            let path_obj = Path::new(path);
+            if path_obj.is_dir() {
+                Err(WcError::IsDirectory(path.to_owned()))
+            } else {
+                let file = File::open(path)?;
+                word_count_from_reader(file, settings, path)
+            }
+        }
+    }
+}
+
+/// Print a message appropriate for the particular error to `stderr`.
+///
+/// # Examples
+///
+/// This will print `wc: /tmp: Is a directory` to `stderr`.
+///
+/// ```rust,ignore
+/// show_error(Input::Path("/tmp"), WcError::IsDirectory("/tmp"))
+/// ```
+fn show_error(input: &Input, err: WcError) {
+    match (input, err) {
+        (_, WcError::IsDirectory(path)) => {
+            show_error_custom_description!(path, "Is a directory");
+        }
+        (Input::Path(path), WcError::Io(e)) if e.kind() == ErrorKind::NotFound => {
+            show_error_custom_description!(path, "No such file or directory");
+        }
+        (_, e) => {
+            show_error!("{}", e);
+        }
+    };
+}
+
+/// Compute the number of digits needed to represent any count for this input.
+///
+/// If `input` is [`Input::Stdin`], then this function returns
+/// [`MINIMUM_WIDTH`]. Otherwise, if metadata could not be read from
+/// `input` then this function returns 1.
+///
+/// # Errors
+///
+/// This function will return an error if `input` is a [`Input::Path`]
+/// and there is a problem accessing the metadata of the given `input`.
+///
+/// # Examples
+///
+/// A [`Input::Stdin`] gets a default minimum width:
+///
+/// ```rust,ignore
+/// let input = Input::Stdin(StdinKind::Explicit);
+/// assert_eq!(7, digit_width(input));
+/// ```
+fn digit_width(input: &Input) -> WcResult<Option<usize>> {
+    match input {
+        Input::Stdin(_) => Ok(Some(MINIMUM_WIDTH)),
+        Input::Path(filename) => {
+            let path = Path::new(filename);
+            let metadata = fs::metadata(path)?;
+            if metadata.is_file() {
+                // TODO We are now computing the number of bytes in a file
+                // twice: once here and once in `WordCount::from_line()` (or
+                // in `count_bytes_fast()` if that function is called
+                // instead). See GitHub issue #2201.
+                let num_bytes = metadata.len();
+                let num_digits = num_bytes.to_string().len();
+                Ok(Some(num_digits))
+            } else {
+                Ok(None)
+            }
+        }
+    }
+}
+
+/// Compute the number of digits needed to represent all counts in all inputs.
+///
+/// `inputs` may include zero or more [`Input::Stdin`] entries, each of
+/// which represents reading from `stdin`. The presence of any such
+/// entry causes this function to return a width that is at least
+/// [`MINIMUM_WIDTH`].
+///
+/// If `input` is empty, then this function returns 1. If file metadata
+/// could not be read from any of the [`Input::Path`] inputs and there
+/// are no [`Input::Stdin`] inputs, then this function returns 1.
+///
+/// If there is a problem accessing the metadata, this function will
+/// silently ignore the error and assume that the number of digits
+/// needed to display the counts for that file is 1.
+///
+/// # Examples
+///
+/// An empty slice implies a width of 1:
+///
+/// ```rust,ignore
+/// assert_eq!(1, max_width(&vec![]));
+/// ```
+///
+/// The presence of [`Input::Stdin`] implies a minimum width:
+///
+/// ```rust,ignore
+/// let inputs = vec![Input::Stdin(StdinKind::Explicit)];
+/// assert_eq!(7, max_width(&inputs));
+/// ```
+fn max_width(inputs: &[Input]) -> usize {
+    let mut result = 1;
+    for input in inputs {
+        if let Ok(Some(n)) = digit_width(input) {
+            result = result.max(n);
+        }
+    }
+    result
+}
+
+fn wc(inputs: Vec<Input>, settings: &Settings) -> Result<(), u32> {
+    // Compute the width, in digits, to use when formatting counts.
+    //
+    // The width is the number of digits needed to print the number of
+    // bytes in the largest file. This is true regardless of whether
+    // the `settings` indicate that the bytes will be displayed.
+    let mut error_count = 0;
+    let max_width = max_width(&inputs);
+
+    let mut total_word_count = WordCount::default();
+
+    let num_inputs = inputs.len();
+
+    for input in &inputs {
+        let word_count = word_count_from_input(input, settings).unwrap_or_else(|err| {
+            show_error(input, err);
+            error_count += 1;
+            WordCount::default()
+        });
+        total_word_count += word_count;
+        let result = word_count.with_title(input.to_title());
+        if let Err(err) = print_stats(settings, &result, max_width) {
+            show_warning!(
+                "failed to print result for {}: {}",
+                result.title.unwrap_or("<stdin>"),
+                err
+            );
+            error_count += 1;
+        }
+    }
+
+    if num_inputs > 1 {
+        let total_result = total_word_count.with_title(Some("total"));
+        if let Err(err) = print_stats(settings, &total_result, max_width) {
+            show_warning!("failed to print total: {}", err);
+            error_count += 1;
+        }
+    }
+
+    if error_count == 0 {
+        Ok(())
+    } else {
+        Err(error_count)
+    }
+}
+
+fn print_stats(
+    settings: &Settings,
+    result: &TitledWordCount,
+    mut min_width: usize,
+) -> WcResult<()> {
+    let stdout = io::stdout();
+    let mut stdout_lock = stdout.lock();
+
+    if settings.number_enabled() <= 1 {
+        // Prevent a leading space in case we only need to display a single
+        // number.
+        min_width = 0;
+    }
+
+    let mut is_first: bool = true;
+
+    if settings.show_lines {
+        if !is_first {
+            write!(stdout_lock, " ")?;
+        }
+        write!(stdout_lock, "{:1$}", result.count.lines, min_width)?;
+        is_first = false;
+    }
+    if settings.show_words {
+        if !is_first {
+            write!(stdout_lock, " ")?;
+        }
+        write!(stdout_lock, "{:1$}", result.count.words, min_width)?;
+        is_first = false;
+    }
+    if settings.show_bytes {
+        if !is_first {
+            write!(stdout_lock, " ")?;
+        }
+        write!(stdout_lock, "{:1$}", result.count.bytes, min_width)?;
+        is_first = false;
+    }
+    if settings.show_chars {
+        if !is_first {
+            write!(stdout_lock, " ")?;
+        }
+        write!(stdout_lock, "{:1$}", result.count.chars, min_width)?;
+        is_first = false;
+    }
+    if settings.show_max_line_length {
+        if !is_first {
+            write!(stdout_lock, " ")?;
+        }
+        write!(
+            stdout_lock,
+            "{:1$}",
+            result.count.max_line_length, min_width
+        )?;
+    }
+
+    if let Some(title) = result.title {
+        writeln!(stdout_lock, " {}", title)?;
+    } else {
+        writeln!(stdout_lock)?;
+    }
+
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uu_wc/word_count.rs.html b/src/uu_wc/word_count.rs.html new file mode 100644 index 000000000..cfa1d2021 --- /dev/null +++ b/src/uu_wc/word_count.rs.html @@ -0,0 +1,267 @@ +word_count.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+
+use std::cmp::max;
+use std::iter::Sum;
+use std::ops::{Add, AddAssign};
+use std::str::from_utf8;
+
+const CR: u8 = b'\r';
+const LF: u8 = b'\n';
+const SPACE: u8 = b' ';
+const TAB: u8 = b'\t';
+const SYN: u8 = 0x16_u8;
+const FF: u8 = 0x0C_u8;
+
+#[inline(always)]
+fn is_word_separator(byte: u8) -> bool {
+    byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF
+}
+
+#[derive(Debug, Default, Copy, Clone)]
+pub struct WordCount {
+    pub bytes: usize,
+    pub chars: usize,
+    pub lines: usize,
+    pub words: usize,
+    pub max_line_length: usize,
+}
+
+impl Add for WordCount {
+    type Output = Self;
+
+    fn add(self, other: Self) -> Self {
+        Self {
+            bytes: self.bytes + other.bytes,
+            chars: self.chars + other.chars,
+            lines: self.lines + other.lines,
+            words: self.words + other.words,
+            max_line_length: max(self.max_line_length, other.max_line_length),
+        }
+    }
+}
+
+impl AddAssign for WordCount {
+    fn add_assign(&mut self, other: Self) {
+        *self = *self + other
+    }
+}
+
+impl Sum for WordCount {
+    fn sum<I>(iter: I) -> WordCount
+    where
+        I: Iterator<Item = WordCount>,
+    {
+        iter.fold(WordCount::default(), |acc, x| acc + x)
+    }
+}
+
+impl WordCount {
+    /// Count the characters and whitespace-separated words in the given bytes.
+    ///
+    /// `line` is a slice of bytes that will be decoded as ASCII characters.
+    fn ascii_word_and_char_count(line: &[u8]) -> (usize, usize) {
+        let word_count = line.split(|&x| is_word_separator(x)).count();
+        let char_count = line.iter().filter(|c| c.is_ascii()).count();
+        (word_count, char_count)
+    }
+
+    /// Create a [`WordCount`] from a sequence of bytes representing a line.
+    ///
+    /// If the last byte of `line` encodes a newline character (`\n`),
+    /// then the [`lines`] field will be set to 1. Otherwise, it will
+    /// be set to 0. The [`bytes`] field is simply the length of
+    /// `line`.
+    ///
+    /// If `decode_chars` is `false`, the [`chars`] and [`words`]
+    /// fields will be set to 0. If it is `true`, this function will
+    /// attempt to decode the bytes first as UTF-8, and failing that,
+    /// as ASCII.
+    pub fn from_line(line: &[u8], decode_chars: bool) -> WordCount {
+        // GNU 'wc' only counts lines that end in LF as lines
+        let lines = (*line.last().unwrap() == LF) as usize;
+        let bytes = line.len();
+        let (words, chars) = if decode_chars {
+            WordCount::word_and_char_count(line)
+        } else {
+            (0, 0)
+        };
+        // -L is a GNU 'wc' extension so same behavior on LF
+        let max_line_length = if chars > 0 { chars - lines } else { 0 };
+        WordCount {
+            bytes,
+            chars,
+            lines,
+            words,
+            max_line_length,
+        }
+    }
+
+    /// Count the UTF-8 characters and words in the given string slice.
+    ///
+    /// `s` is a string slice that is assumed to be a UTF-8 string.
+    fn utf8_word_and_char_count(s: &str) -> (usize, usize) {
+        let word_count = s.split_whitespace().count();
+        let char_count = s.chars().count();
+        (word_count, char_count)
+    }
+
+    pub fn with_title(self, title: Option<&str>) -> TitledWordCount {
+        TitledWordCount { title, count: self }
+    }
+
+    /// Count the characters and words in the given slice of bytes.
+    ///
+    /// `line` is a slice of bytes that will be decoded as UTF-8
+    /// characters, or if that fails, as ASCII characters.
+    fn word_and_char_count(line: &[u8]) -> (usize, usize) {
+        // try and convert the bytes to UTF-8 first
+        match from_utf8(line) {
+            Ok(s) => WordCount::utf8_word_and_char_count(s),
+            Err(..) => WordCount::ascii_word_and_char_count(line),
+        }
+    }
+}
+
+/// This struct supplements the actual word count with an optional title that is
+/// displayed to the user at the end of the program.
+/// The reason we don't simply include title in the `WordCount` struct is that
+/// it would result in unnecessary copying of `String`.
+#[derive(Debug, Default, Clone)]
+pub struct TitledWordCount<'a> {
+    pub title: Option<&'a str>,
+    pub count: WordCount,
+}
+
+
\ No newline at end of file diff --git a/src/uu_who/who.rs.html b/src/uu_who/who.rs.html new file mode 100644 index 000000000..db77ac517 --- /dev/null +++ b/src/uu_who/who.rs.html @@ -0,0 +1,1117 @@ +who.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) ttyname hostnames runlevel mesg wtmp statted boottime deadprocs initspawn clockchange curr runlvline pidstr exitstr hoststr
+
+#[macro_use]
+extern crate uucore;
+use uucore::libc::{ttyname, STDIN_FILENO, S_IWGRP};
+use uucore::utmpx::{self, time, Utmpx};
+
+use clap::{crate_version, App, Arg};
+use std::borrow::Cow;
+use std::ffi::CStr;
+use std::os::unix::fs::MetadataExt;
+use std::path::PathBuf;
+use uucore::InvalidEncodingHandling;
+
+mod options {
+    pub const ALL: &str = "all";
+    pub const BOOT: &str = "boot";
+    pub const DEAD: &str = "dead";
+    pub const HEADING: &str = "heading";
+    pub const LOGIN: &str = "login";
+    pub const LOOKUP: &str = "lookup";
+    pub const ONLY_HOSTNAME_USER: &str = "only_hostname_user";
+    pub const PROCESS: &str = "process";
+    pub const COUNT: &str = "count";
+    pub const RUNLEVEL: &str = "runlevel";
+    pub const SHORT: &str = "short";
+    pub const TIME: &str = "time";
+    pub const USERS: &str = "users";
+    pub const MESG: &str = "mesg"; // aliases: --message, --writable
+    pub const FILE: &str = "FILE"; // if length=1: FILE, if length=2: ARG1 ARG2
+}
+
+static ABOUT: &str = "Print information about users who are currently logged in.";
+
+#[cfg(any(target_os = "linux"))]
+static RUNLEVEL_HELP: &str = "print current runlevel";
+#[cfg(not(target_os = "linux"))]
+static RUNLEVEL_HELP: &str = "print current runlevel (This is meaningless on non Linux)";
+
+fn usage() -> String {
+    format!(
+        "{0} [OPTION]... [ FILE | ARG1 ARG2 ]",
+        uucore::execution_phrase()
+    )
+}
+
+fn get_long_usage() -> String {
+    format!(
+        "If FILE is not specified, use {}.  /var/log/wtmp as FILE is common.\n\
+         If ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.",
+        utmpx::DEFAULT_FILE,
+    )
+}
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let args = args
+        .collect_str(InvalidEncodingHandling::Ignore)
+        .accept_any();
+
+    let usage = usage();
+    let after_help = get_long_usage();
+
+    let matches = uu_app()
+        .usage(&usage[..])
+        .after_help(&after_help[..])
+        .get_matches_from(args);
+
+    let files: Vec<String> = matches
+        .values_of(options::FILE)
+        .map(|v| v.map(ToString::to_string).collect())
+        .unwrap_or_default();
+
+    // If true, attempt to canonicalize hostnames via a DNS lookup.
+    let do_lookup = matches.is_present(options::LOOKUP);
+
+    // If true, display only a list of usernames and count of
+    // the users logged on.
+    // Ignored for 'who am i'.
+    let short_list = matches.is_present(options::COUNT);
+
+    let all = matches.is_present(options::ALL);
+
+    // If true, display a line at the top describing each field.
+    let include_heading = matches.is_present(options::HEADING);
+
+    // If true, display a '+' for each user if mesg y, a '-' if mesg n,
+    // or a '?' if their tty cannot be statted.
+    let include_mesg = all || matches.is_present(options::MESG) || matches.is_present("w");
+
+    // If true, display the last boot time.
+    let need_boottime = all || matches.is_present(options::BOOT);
+
+    // If true, display dead processes.
+    let need_deadprocs = all || matches.is_present(options::DEAD);
+
+    // If true, display processes waiting for user login.
+    let need_login = all || matches.is_present(options::LOGIN);
+
+    // If true, display processes started by init.
+    let need_initspawn = all || matches.is_present(options::PROCESS);
+
+    // If true, display the last clock change.
+    let need_clockchange = all || matches.is_present(options::TIME);
+
+    // If true, display the current runlevel.
+    let need_runlevel = all || matches.is_present(options::RUNLEVEL);
+
+    let use_defaults = !(all
+        || need_boottime
+        || need_deadprocs
+        || need_login
+        || need_initspawn
+        || need_runlevel
+        || need_clockchange
+        || matches.is_present(options::USERS));
+
+    // If true, display user processes.
+    let need_users = all || matches.is_present(options::USERS) || use_defaults;
+
+    // If true, display the hours:minutes since each user has touched
+    // the keyboard, or "." if within the last minute, or "old" if
+    // not within the last day.
+    let include_idle = need_deadprocs || need_login || need_runlevel || need_users;
+
+    // If true, display process termination & exit status.
+    let include_exit = need_deadprocs;
+
+    // If true, display only name, line, and time fields.
+    let short_output = !include_exit && use_defaults;
+
+    // If true, display info only for the controlling tty.
+    let my_line_only = matches.is_present(options::ONLY_HOSTNAME_USER) || files.len() == 2;
+
+    let mut who = Who {
+        do_lookup,
+        short_list,
+        short_output,
+        include_idle,
+        include_heading,
+        include_mesg,
+        include_exit,
+        need_boottime,
+        need_deadprocs,
+        need_login,
+        need_initspawn,
+        need_clockchange,
+        need_runlevel,
+        need_users,
+        my_line_only,
+        args: files,
+    };
+
+    who.exec();
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    App::new(uucore::util_name())
+        .version(crate_version!())
+        .about(ABOUT)
+        .arg(
+            Arg::with_name(options::ALL)
+                .long(options::ALL)
+                .short("a")
+                .help("same as -b -d --login -p -r -t -T -u"),
+        )
+        .arg(
+            Arg::with_name(options::BOOT)
+                .long(options::BOOT)
+                .short("b")
+                .help("time of last system boot"),
+        )
+        .arg(
+            Arg::with_name(options::DEAD)
+                .long(options::DEAD)
+                .short("d")
+                .help("print dead processes"),
+        )
+        .arg(
+            Arg::with_name(options::HEADING)
+                .long(options::HEADING)
+                .short("H")
+                .help("print line of column headings"),
+        )
+        .arg(
+            Arg::with_name(options::LOGIN)
+                .long(options::LOGIN)
+                .short("l")
+                .help("print system login processes"),
+        )
+        .arg(
+            Arg::with_name(options::LOOKUP)
+                .long(options::LOOKUP)
+                .help("attempt to canonicalize hostnames via DNS"),
+        )
+        .arg(
+            Arg::with_name(options::ONLY_HOSTNAME_USER)
+                .short("m")
+                .help("only hostname and user associated with stdin"),
+        )
+        .arg(
+            Arg::with_name(options::PROCESS)
+                .long(options::PROCESS)
+                .short("p")
+                .help("print active processes spawned by init"),
+        )
+        .arg(
+            Arg::with_name(options::COUNT)
+                .long(options::COUNT)
+                .short("q")
+                .help("all login names and number of users logged on"),
+        )
+        .arg(
+            Arg::with_name(options::RUNLEVEL)
+                .long(options::RUNLEVEL)
+                .short("r")
+                .help(RUNLEVEL_HELP),
+        )
+        .arg(
+            Arg::with_name(options::SHORT)
+                .long(options::SHORT)
+                .short("s")
+                .help("print only name, line, and time (default)"),
+        )
+        .arg(
+            Arg::with_name(options::TIME)
+                .long(options::TIME)
+                .short("t")
+                .help("print last system clock change"),
+        )
+        .arg(
+            Arg::with_name(options::USERS)
+                .long(options::USERS)
+                .short("u")
+                .help("list users logged in"),
+        )
+        .arg(
+            Arg::with_name(options::MESG)
+                .long(options::MESG)
+                .short("T")
+                // .visible_short_alias('w')  // TODO: requires clap "3.0.0-beta.2"
+                .visible_aliases(&["message", "writable"])
+                .help("add user's message status as +, - or ?"),
+        )
+        .arg(
+            Arg::with_name("w") // work around for `Arg::visible_short_alias`
+                .short("w")
+                .help("same as -T"),
+        )
+        .arg(
+            Arg::with_name(options::FILE)
+                .takes_value(true)
+                .min_values(1)
+                .max_values(2),
+        )
+}
+
+struct Who {
+    do_lookup: bool,
+    short_list: bool,
+    short_output: bool,
+    include_idle: bool,
+    include_heading: bool,
+    include_mesg: bool,
+    include_exit: bool,
+    need_boottime: bool,
+    need_deadprocs: bool,
+    need_login: bool,
+    need_initspawn: bool,
+    need_clockchange: bool,
+    need_runlevel: bool,
+    need_users: bool,
+    my_line_only: bool,
+    args: Vec<String>,
+}
+
+fn idle_string<'a>(when: i64, boottime: i64) -> Cow<'a, str> {
+    thread_local! {
+        static NOW: time::Tm = time::now()
+    }
+    NOW.with(|n| {
+        let now = n.to_timespec().sec;
+        if boottime < when && now - 24 * 3600 < when && when <= now {
+            let seconds_idle = now - when;
+            if seconds_idle < 60 {
+                "  .  ".into()
+            } else {
+                format!(
+                    "{:02}:{:02}",
+                    seconds_idle / 3600,
+                    (seconds_idle % 3600) / 60
+                )
+                .into()
+            }
+        } else {
+            " old ".into()
+        }
+    })
+}
+
+fn time_string(ut: &Utmpx) -> String {
+    time::strftime("%b %e %H:%M", &ut.login_time()).unwrap() // LC_ALL=C
+}
+
+#[inline]
+fn current_tty() -> String {
+    unsafe {
+        let res = ttyname(STDIN_FILENO);
+        if !res.is_null() {
+            CStr::from_ptr(res as *const _)
+                .to_string_lossy()
+                .trim_start_matches("/dev/")
+                .to_owned()
+        } else {
+            "".to_owned()
+        }
+    }
+}
+
+impl Who {
+    fn exec(&mut self) {
+        let run_level_chk = |_record: i16| {
+            #[cfg(not(target_os = "linux"))]
+            return false;
+
+            #[cfg(target_os = "linux")]
+            return _record == utmpx::RUN_LVL;
+        };
+
+        let f = if self.args.len() == 1 {
+            self.args[0].as_ref()
+        } else {
+            utmpx::DEFAULT_FILE
+        };
+        if self.short_list {
+            let users = Utmpx::iter_all_records()
+                .read_from(f)
+                .filter(Utmpx::is_user_process)
+                .map(|ut| ut.user())
+                .collect::<Vec<_>>();
+            println!("{}", users.join(" "));
+            println!("# users={}", users.len());
+        } else {
+            let records = Utmpx::iter_all_records().read_from(f).peekable();
+
+            if self.include_heading {
+                self.print_heading()
+            }
+            let cur_tty = if self.my_line_only {
+                current_tty()
+            } else {
+                "".to_owned()
+            };
+
+            for ut in records {
+                if !self.my_line_only || cur_tty == ut.tty_device() {
+                    if self.need_users && ut.is_user_process() {
+                        self.print_user(&ut);
+                    } else if self.need_runlevel && run_level_chk(ut.record_type()) {
+                        if cfg!(target_os = "linux") {
+                            self.print_runlevel(&ut);
+                        }
+                    } else if self.need_boottime && ut.record_type() == utmpx::BOOT_TIME {
+                        self.print_boottime(&ut);
+                    } else if self.need_clockchange && ut.record_type() == utmpx::NEW_TIME {
+                        self.print_clockchange(&ut);
+                    } else if self.need_initspawn && ut.record_type() == utmpx::INIT_PROCESS {
+                        self.print_initspawn(&ut);
+                    } else if self.need_login && ut.record_type() == utmpx::LOGIN_PROCESS {
+                        self.print_login(&ut);
+                    } else if self.need_deadprocs && ut.record_type() == utmpx::DEAD_PROCESS {
+                        self.print_deadprocs(&ut);
+                    }
+                }
+
+                if ut.record_type() == utmpx::BOOT_TIME {}
+            }
+        }
+    }
+
+    #[inline]
+    fn print_runlevel(&self, ut: &Utmpx) {
+        let last = (ut.pid() / 256) as u8 as char;
+        let curr = (ut.pid() % 256) as u8 as char;
+        let runlvline = format!("run-level {}", curr);
+        let comment = format!("last={}", if last == 'N' { 'S' } else { 'N' });
+
+        self.print_line(
+            "",
+            ' ',
+            &runlvline,
+            &time_string(ut),
+            "",
+            "",
+            if !last.is_control() { &comment } else { "" },
+            "",
+        );
+    }
+
+    #[inline]
+    fn print_clockchange(&self, ut: &Utmpx) {
+        self.print_line("", ' ', "clock change", &time_string(ut), "", "", "", "");
+    }
+
+    #[inline]
+    fn print_login(&self, ut: &Utmpx) {
+        let comment = format!("id={}", ut.terminal_suffix());
+        let pidstr = format!("{}", ut.pid());
+        self.print_line(
+            "LOGIN",
+            ' ',
+            &ut.tty_device(),
+            &time_string(ut),
+            "",
+            &pidstr,
+            &comment,
+            "",
+        );
+    }
+
+    #[inline]
+    fn print_deadprocs(&self, ut: &Utmpx) {
+        let comment = format!("id={}", ut.terminal_suffix());
+        let pidstr = format!("{}", ut.pid());
+        let e = ut.exit_status();
+        let exitstr = format!("term={} exit={}", e.0, e.1);
+        self.print_line(
+            "",
+            ' ',
+            &ut.tty_device(),
+            &time_string(ut),
+            "",
+            &pidstr,
+            &comment,
+            &exitstr,
+        );
+    }
+
+    #[inline]
+    fn print_initspawn(&self, ut: &Utmpx) {
+        let comment = format!("id={}", ut.terminal_suffix());
+        let pidstr = format!("{}", ut.pid());
+        self.print_line(
+            "",
+            ' ',
+            &ut.tty_device(),
+            &time_string(ut),
+            "",
+            &pidstr,
+            &comment,
+            "",
+        );
+    }
+
+    #[inline]
+    fn print_boottime(&self, ut: &Utmpx) {
+        self.print_line("", ' ', "system boot", &time_string(ut), "", "", "", "");
+    }
+
+    fn print_user(&self, ut: &Utmpx) {
+        let mut p = PathBuf::from("/dev");
+        p.push(ut.tty_device().as_str());
+        let mesg;
+        let last_change;
+        match p.metadata() {
+            Ok(meta) => {
+                mesg = if meta.mode() & (S_IWGRP as u32) != 0 {
+                    '+'
+                } else {
+                    '-'
+                };
+                last_change = meta.atime();
+            }
+            _ => {
+                mesg = '?';
+                last_change = 0;
+            }
+        }
+
+        let idle = if last_change != 0 {
+            idle_string(last_change, 0)
+        } else {
+            "  ?".into()
+        };
+
+        let s = if self.do_lookup {
+            safe_unwrap!(ut.canon_host())
+        } else {
+            ut.host()
+        };
+        let hoststr = if s.is_empty() { s } else { format!("({})", s) };
+
+        self.print_line(
+            ut.user().as_ref(),
+            mesg,
+            ut.tty_device().as_ref(),
+            time_string(ut).as_str(),
+            idle.as_ref(),
+            format!("{}", ut.pid()).as_str(),
+            hoststr.as_str(),
+            "",
+        );
+    }
+
+    #[allow(clippy::too_many_arguments)]
+    fn print_line(
+        &self,
+        user: &str,
+        state: char,
+        line: &str,
+        time: &str,
+        idle: &str,
+        pid: &str,
+        comment: &str,
+        exit: &str,
+    ) {
+        let mut buf = String::with_capacity(64);
+        let msg = vec![' ', state].into_iter().collect::<String>();
+
+        buf.push_str(&format!("{:<8}", user));
+        if self.include_mesg {
+            buf.push_str(&msg);
+        }
+        buf.push_str(&format!(" {:<12}", line));
+        // "%b %e %H:%M" (LC_ALL=C)
+        let time_size = 3 + 2 + 2 + 1 + 2;
+        buf.push_str(&format!(" {:<1$}", time, time_size));
+
+        if !self.short_output {
+            if self.include_idle {
+                buf.push_str(&format!(" {:<6}", idle));
+            }
+            buf.push_str(&format!(" {:>10}", pid));
+        }
+        buf.push_str(&format!(" {:<8}", comment));
+        if self.include_exit {
+            buf.push_str(&format!(" {:<12}", exit));
+        }
+        println!("{}", buf.trim_end());
+    }
+
+    #[inline]
+    fn print_heading(&self) {
+        self.print_line(
+            "NAME", ' ', "LINE", "TIME", "IDLE", "PID", "COMMENT", "EXIT",
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_whoami/platform/mod.rs.html b/src/uu_whoami/platform/mod.rs.html new file mode 100644 index 000000000..be85ea27f --- /dev/null +++ b/src/uu_whoami/platform/mod.rs.html @@ -0,0 +1,49 @@ +mod.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+
+/*
+ * This file is part of the uutils coreutils package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+// spell-checker:ignore (ToDO) getusername
+
+#[cfg(unix)]
+pub use self::unix::get_username;
+
+#[cfg(windows)]
+pub use self::windows::get_username;
+
+#[cfg(unix)]
+mod unix;
+
+#[cfg(windows)]
+mod windows;
+
+
\ No newline at end of file diff --git a/src/uu_whoami/platform/unix.rs.html b/src/uu_whoami/platform/unix.rs.html new file mode 100644 index 000000000..5f26f3c43 --- /dev/null +++ b/src/uu_whoami/platform/unix.rs.html @@ -0,0 +1,47 @@ +unix.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+
+/*
+ * This file is part of the uutils coreutils package.
+ *
+ * (c) Jordi Boggiano <j.boggiano@seld.be>
+ * (c) Jian Zeng <anonymousknight96 AT gmail.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+// spell-checker:ignore (ToDO) getusername
+
+use std::io::Result;
+use uucore::entries::uid2usr;
+use uucore::libc::geteuid;
+
+pub unsafe fn get_username() -> Result<String> {
+    // Get effective user id
+    let uid = geteuid();
+    uid2usr(uid)
+}
+
+
\ No newline at end of file diff --git a/src/uu_whoami/whoami.rs.html b/src/uu_whoami/whoami.rs.html new file mode 100644 index 000000000..5f173ea1f --- /dev/null +++ b/src/uu_whoami/whoami.rs.html @@ -0,0 +1,111 @@ +whoami.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+
+use clap::App;
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+/* last synced with: whoami (GNU coreutils) 8.21 */
+
+#[macro_use]
+extern crate clap;
+#[macro_use]
+extern crate uucore;
+
+mod platform;
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let app = uu_app();
+
+    if let Err(err) = app.get_matches_from_safe(args) {
+        if err.kind == clap::ErrorKind::HelpDisplayed
+            || err.kind == clap::ErrorKind::VersionDisplayed
+        {
+            println!("{}", err);
+            0
+        } else {
+            show_error!("{}", err);
+            1
+        }
+    } else {
+        exec();
+
+        0
+    }
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    app_from_crate!()
+}
+
+pub fn exec() {
+    unsafe {
+        match platform::get_username() {
+            Ok(username) => println!("{}", username),
+            Err(err) => match err.raw_os_error() {
+                Some(0) | None => crash!(1, "failed to get username"),
+                Some(_) => crash!(1, "failed to get username: {}", err),
+            },
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uu_yes/yes.rs.html b/src/uu_yes/yes.rs.html new file mode 100644 index 000000000..787097c22 --- /dev/null +++ b/src/uu_yes/yes.rs.html @@ -0,0 +1,185 @@ +yes.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * (c) Jordi Boggiano <j.boggiano@seld.be>
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+/* last synced with: yes (GNU coreutils) 8.13 */
+
+#[macro_use]
+extern crate clap;
+#[macro_use]
+extern crate uucore;
+
+use clap::{App, Arg};
+use std::borrow::Cow;
+use std::io::{self, Write};
+use uucore::zero_copy::ZeroCopyWriter;
+
+// it's possible that using a smaller or larger buffer might provide better performance on some
+// systems, but honestly this is good enough
+const BUF_SIZE: usize = 16 * 1024;
+
+pub fn uumain(args: impl uucore::Args) -> i32 {
+    let app = uu_app();
+
+    let matches = match app.get_matches_from_safe(args) {
+        Ok(m) => m,
+        Err(ref e)
+            if e.kind == clap::ErrorKind::HelpDisplayed
+                || e.kind == clap::ErrorKind::VersionDisplayed =>
+        {
+            println!("{}", e);
+            return 0;
+        }
+        Err(f) => {
+            show_error!("{}", f);
+            return 1;
+        }
+    };
+
+    let string = if let Some(values) = matches.values_of("STRING") {
+        let mut result = values.fold(String::new(), |res, s| res + s + " ");
+        result.pop();
+        result.push('\n');
+        Cow::from(result)
+    } else {
+        Cow::from("y\n")
+    };
+
+    let mut buffer = [0; BUF_SIZE];
+    let bytes = prepare_buffer(&string, &mut buffer);
+
+    exec(bytes);
+
+    0
+}
+
+pub fn uu_app() -> App<'static, 'static> {
+    app_from_crate!().arg(Arg::with_name("STRING").index(1).multiple(true))
+}
+
+#[cfg(not(feature = "latency"))]
+fn prepare_buffer<'a>(input: &'a str, buffer: &'a mut [u8; BUF_SIZE]) -> &'a [u8] {
+    if input.len() < BUF_SIZE / 2 {
+        let mut size = 0;
+        while size < BUF_SIZE - input.len() {
+            let (_, right) = buffer.split_at_mut(size);
+            right[..input.len()].copy_from_slice(input.as_bytes());
+            size += input.len();
+        }
+        &buffer[..size]
+    } else {
+        input.as_bytes()
+    }
+}
+
+#[cfg(feature = "latency")]
+fn prepare_buffer<'a>(input: &'a str, _buffer: &'a mut [u8; BUF_SIZE]) -> &'a [u8] {
+    input.as_bytes()
+}
+
+pub fn exec(bytes: &[u8]) {
+    let mut stdout_raw = io::stdout();
+    let mut writer = ZeroCopyWriter::with_default(&mut stdout_raw, |stdout| stdout.lock());
+    loop {
+        // TODO: needs to check if pipe fails
+        writer.write_all(bytes).unwrap();
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features.rs.html b/src/uucore/features.rs.html new file mode 100644 index 000000000..ea0829be2 --- /dev/null +++ b/src/uucore/features.rs.html @@ -0,0 +1,83 @@ +features.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+
+// features ~ feature-gated modules (core/bundler file)
+
+#[cfg(feature = "encoding")]
+pub mod encoding;
+#[cfg(feature = "fs")]
+pub mod fs;
+#[cfg(feature = "fsext")]
+pub mod fsext;
+#[cfg(feature = "ringbuffer")]
+pub mod ringbuffer;
+#[cfg(feature = "zero-copy")]
+pub mod zero_copy;
+
+// * (platform-specific) feature-gated modules
+// ** non-windows
+#[cfg(all(not(windows), feature = "mode"))]
+pub mod mode;
+
+// ** unix-only
+#[cfg(all(unix, feature = "entries"))]
+pub mod entries;
+#[cfg(all(unix, feature = "perms"))]
+pub mod perms;
+#[cfg(all(unix, feature = "process"))]
+pub mod process;
+
+#[cfg(all(unix, not(target_os = "fuchsia"), feature = "signals"))]
+pub mod signals;
+#[cfg(all(
+    unix,
+    not(target_os = "fuchsia"),
+    not(target_os = "redox"),
+    not(target_env = "musl"),
+    feature = "utmpx"
+))]
+pub mod utmpx;
+// ** windows-only
+#[cfg(all(windows, feature = "wide"))]
+pub mod wide;
+
+
\ No newline at end of file diff --git a/src/uucore/features/encoding.rs.html b/src/uucore/features/encoding.rs.html new file mode 100644 index 000000000..ac221a4ba --- /dev/null +++ b/src/uucore/features/encoding.rs.html @@ -0,0 +1,359 @@ +encoding.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (strings) ABCDEFGHIJKLMNOPQRSTUVWXYZ ABCDEFGHIJKLMNOPQRSTUV
+// spell-checker:ignore (encodings) lsbf msbf hexupper
+
+use data_encoding::{self, BASE32, BASE64};
+
+use std::io::{self, Read, Write};
+
+use data_encoding::{Encoding, BASE32HEX, BASE64URL, HEXUPPER};
+use data_encoding_macro::new_encoding;
+#[cfg(feature = "thiserror")]
+use thiserror::Error;
+
+#[derive(Debug, Error)]
+pub enum DecodeError {
+    #[error("{}", _0)]
+    Decode(#[from] data_encoding::DecodeError),
+    #[error("{}", _0)]
+    DecodeZ85(#[from] z85::DecodeError),
+    #[error("{}", _0)]
+    Io(#[from] io::Error),
+}
+
+pub enum EncodeError {
+    Z85InputLenNotMultipleOf4,
+}
+
+pub type DecodeResult = Result<Vec<u8>, DecodeError>;
+
+#[derive(Clone, Copy)]
+pub enum Format {
+    Base64,
+    Base64Url,
+    Base32,
+    Base32Hex,
+    Base16,
+    Base2Lsbf,
+    Base2Msbf,
+    Z85,
+}
+use self::Format::*;
+
+const BASE2LSBF: Encoding = new_encoding! {
+    symbols: "01",
+    bit_order: LeastSignificantFirst,
+};
+const BASE2MSBF: Encoding = new_encoding! {
+    symbols: "01",
+    bit_order: MostSignificantFirst,
+};
+
+pub fn encode(f: Format, input: &[u8]) -> Result<String, EncodeError> {
+    Ok(match f {
+        Base32 => BASE32.encode(input),
+        Base64 => BASE64.encode(input),
+        Base64Url => BASE64URL.encode(input),
+        Base32Hex => BASE32HEX.encode(input),
+        Base16 => HEXUPPER.encode(input),
+        Base2Lsbf => BASE2LSBF.encode(input),
+        Base2Msbf => BASE2MSBF.encode(input),
+        Z85 => {
+            // According to the spec we should not accept inputs whose len is not a multiple of 4.
+            // However, the z85 crate implements a padded encoding and accepts such inputs. We have to manually check for them.
+            if input.len() % 4 != 0 {
+                return Err(EncodeError::Z85InputLenNotMultipleOf4);
+            } else {
+                z85::encode(input)
+            }
+        }
+    })
+}
+
+pub fn decode(f: Format, input: &[u8]) -> DecodeResult {
+    Ok(match f {
+        Base32 => BASE32.decode(input)?,
+        Base64 => BASE64.decode(input)?,
+        Base64Url => BASE64URL.decode(input)?,
+        Base32Hex => BASE32HEX.decode(input)?,
+        Base16 => HEXUPPER.decode(input)?,
+        Base2Lsbf => BASE2LSBF.decode(input)?,
+        Base2Msbf => BASE2MSBF.decode(input)?,
+        Z85 => {
+            // The z85 crate implements a padded encoding by using a leading '#' which is otherwise not allowed.
+            // We manually check for a leading '#' and return an error ourselves.
+            if input.starts_with(&[b'#']) {
+                return Err(z85::DecodeError::InvalidByte(0, b'#').into());
+            } else {
+                z85::decode(input)?
+            }
+        }
+    })
+}
+
+pub struct Data<R: Read> {
+    line_wrap: usize,
+    ignore_garbage: bool,
+    input: R,
+    format: Format,
+    alphabet: &'static [u8],
+}
+
+impl<R: Read> Data<R> {
+    pub fn new(input: R, format: Format) -> Self {
+        Data {
+            line_wrap: 76,
+            ignore_garbage: false,
+            input,
+            format,
+            alphabet: match format {
+                Base32 => b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
+                Base64 => b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=+/",
+                Base64Url => b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789=_-",
+                Base32Hex => b"0123456789ABCDEFGHIJKLMNOPQRSTUV=",
+                Base16 => b"0123456789ABCDEF",
+                Base2Lsbf => b"01",
+                Base2Msbf => b"01",
+                Z85 => b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-:+=^!/*?&<>()[]{}@%$#",
+            },
+        }
+    }
+
+    pub fn line_wrap(mut self, wrap: usize) -> Self {
+        self.line_wrap = wrap;
+        self
+    }
+
+    pub fn ignore_garbage(mut self, ignore: bool) -> Self {
+        self.ignore_garbage = ignore;
+        self
+    }
+
+    pub fn decode(&mut self) -> DecodeResult {
+        let mut buf = vec![];
+        self.input.read_to_end(&mut buf)?;
+        if self.ignore_garbage {
+            buf.retain(|c| self.alphabet.contains(c));
+        } else {
+            buf.retain(|&c| c != b'\r' && c != b'\n');
+        };
+        decode(self.format, &buf)
+    }
+
+    pub fn encode(&mut self) -> Result<String, EncodeError> {
+        let mut buf: Vec<u8> = vec![];
+        self.input.read_to_end(&mut buf).unwrap();
+        encode(self.format, buf.as_slice())
+    }
+}
+
+// NOTE: this will likely be phased out at some point
+pub fn wrap_print<R: Read>(data: &Data<R>, res: String) {
+    let stdout = io::stdout();
+    wrap_write(stdout.lock(), data.line_wrap, res).unwrap();
+}
+
+pub fn wrap_write<W: Write>(mut writer: W, line_wrap: usize, res: String) -> io::Result<()> {
+    use std::cmp::min;
+
+    if line_wrap == 0 {
+        return write!(writer, "{}", res);
+    }
+
+    let mut start = 0;
+    while start < res.len() {
+        let end = min(start + line_wrap, res.len());
+        writeln!(writer, "{}", &res[start..end])?;
+        start = end;
+    }
+
+    Ok(())
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/entries.rs.html b/src/uucore/features/entries.rs.html new file mode 100644 index 000000000..3b80d135c --- /dev/null +++ b/src/uucore/features/entries.rs.html @@ -0,0 +1,749 @@ +entries.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (vars) Passwd cstr fnam gecos ngroups egid
+
+//! Get password/group file entry
+//!
+//! # Examples:
+//!
+//! ```
+//! use uucore::entries::{self, Locate};
+//!
+//! let root_group = if cfg!(any(target_os = "linux", target_os = "android")) {
+//!     "root"
+//! } else {
+//!     "wheel"
+//! };
+//!
+//! assert_eq!("root", entries::uid2usr(0).unwrap());
+//! assert_eq!(0, entries::usr2uid("root").unwrap());
+//! assert!(entries::gid2grp(0).is_ok());
+//! assert!(entries::grp2gid(root_group).is_ok());
+//!
+//! assert!(entries::Passwd::locate(0).is_ok());
+//! assert!(entries::Passwd::locate("0").is_ok());
+//! assert!(entries::Passwd::locate("root").is_ok());
+//!
+//! assert!(entries::Group::locate(0).is_ok());
+//! assert!(entries::Group::locate("0").is_ok());
+//! assert!(entries::Group::locate(root_group).is_ok());
+//! ```
+
+#[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
+use libc::time_t;
+use libc::{c_char, c_int, gid_t, uid_t};
+#[cfg(not(target_os = "redox"))]
+use libc::{getgrgid, getgrnam, getgroups};
+use libc::{getpwnam, getpwuid, group, passwd};
+
+use std::borrow::Cow;
+use std::ffi::{CStr, CString};
+use std::io::Error as IOError;
+use std::io::ErrorKind;
+use std::io::Result as IOResult;
+use std::ptr;
+
+extern "C" {
+    /// From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html
+    /// > The getgrouplist() function scans the group database to obtain
+    /// > the list of groups that user belongs to.
+    fn getgrouplist(
+        name: *const c_char,
+        gid: gid_t,
+        groups: *mut gid_t,
+        ngroups: *mut c_int,
+    ) -> c_int;
+}
+
+/// From: https://man7.org/linux/man-pages/man2/getgroups.2.html
+/// > getgroups() returns the supplementary group IDs of the calling
+/// > process in list.
+/// > If size is zero, list is not modified, but the total number of
+/// > supplementary group IDs for the process is returned.  This allows
+/// > the caller to determine the size of a dynamically allocated list
+/// > to be used in a further call to getgroups().
+#[cfg(not(target_os = "redox"))]
+pub fn get_groups() -> IOResult<Vec<gid_t>> {
+    let ngroups = unsafe { getgroups(0, ptr::null_mut()) };
+    if ngroups == -1 {
+        return Err(IOError::last_os_error());
+    }
+    let mut groups = Vec::with_capacity(ngroups as usize);
+    let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) };
+    if ngroups == -1 {
+        Err(IOError::last_os_error())
+    } else {
+        unsafe {
+            groups.set_len(ngroups as usize);
+        }
+        Ok(groups)
+    }
+}
+
+/// The list of group IDs returned from GNU's `groups` and GNU's `id --groups`
+/// starts with the effective group ID (egid).
+/// This is a wrapper for `get_groups()` to mimic this behavior.
+///
+/// If `arg_id` is `None` (default), `get_groups_gnu` moves the effective
+/// group id (egid) to the first entry in the returned Vector.
+/// If `arg_id` is `Some(x)`, `get_groups_gnu` moves the id with value `x`
+/// to the first entry in the returned Vector. This might be necessary
+/// for `id --groups --real` if `gid` and `egid` are not equal.
+///
+/// From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html
+/// > As implied by the definition of supplementary groups, the
+/// > effective group ID may appear in the array returned by
+/// > getgroups() or it may be returned only by getegid().  Duplication
+/// > may exist, but the application needs to call getegid() to be sure
+/// > of getting all of the information. Various implementation
+/// > variations and administrative sequences cause the set of groups
+/// > appearing in the result of getgroups() to vary in order and as to
+/// > whether the effective group ID is included, even when the set of
+/// > groups is the same (in the mathematical sense of ``set''). (The
+/// > history of a process and its parents could affect the details of
+/// > the result.)
+#[cfg(all(unix, not(target_os = "redox"), feature = "process"))]
+pub fn get_groups_gnu(arg_id: Option<u32>) -> IOResult<Vec<gid_t>> {
+    let groups = get_groups()?;
+    let egid = arg_id.unwrap_or_else(crate::features::process::getegid);
+    Ok(sort_groups(groups, egid))
+}
+
+#[cfg(all(unix, feature = "process"))]
+fn sort_groups(mut groups: Vec<gid_t>, egid: gid_t) -> Vec<gid_t> {
+    if let Some(index) = groups.iter().position(|&x| x == egid) {
+        groups[..=index].rotate_right(1);
+    } else {
+        groups.insert(0, egid);
+    }
+    groups
+}
+
+#[derive(Copy, Clone)]
+pub struct Passwd {
+    inner: passwd,
+}
+
+macro_rules! cstr2cow {
+    ($v:expr) => {
+        unsafe { CStr::from_ptr($v).to_string_lossy() }
+    };
+}
+
+impl Passwd {
+    /// AKA passwd.pw_name
+    pub fn name(&self) -> Cow<str> {
+        cstr2cow!(self.inner.pw_name)
+    }
+
+    /// AKA passwd.pw_uid
+    pub fn uid(&self) -> uid_t {
+        self.inner.pw_uid
+    }
+
+    /// AKA passwd.pw_gid
+    pub fn gid(&self) -> gid_t {
+        self.inner.pw_gid
+    }
+
+    /// AKA passwd.pw_gecos
+    pub fn user_info(&self) -> Cow<str> {
+        cstr2cow!(self.inner.pw_gecos)
+    }
+
+    /// AKA passwd.pw_shell
+    pub fn user_shell(&self) -> Cow<str> {
+        cstr2cow!(self.inner.pw_shell)
+    }
+
+    /// AKA passwd.pw_dir
+    pub fn user_dir(&self) -> Cow<str> {
+        cstr2cow!(self.inner.pw_dir)
+    }
+
+    /// AKA passwd.pw_passwd
+    pub fn user_passwd(&self) -> Cow<str> {
+        cstr2cow!(self.inner.pw_passwd)
+    }
+
+    /// AKA passwd.pw_class
+    #[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
+    pub fn user_access_class(&self) -> Cow<str> {
+        cstr2cow!(self.inner.pw_class)
+    }
+
+    /// AKA passwd.pw_change
+    #[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
+    pub fn passwd_change_time(&self) -> time_t {
+        self.inner.pw_change
+    }
+
+    /// AKA passwd.pw_expire
+    #[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
+    pub fn expiration(&self) -> time_t {
+        self.inner.pw_expire
+    }
+
+    pub fn as_inner(&self) -> &passwd {
+        &self.inner
+    }
+
+    pub fn into_inner(self) -> passwd {
+        self.inner
+    }
+
+    /// This is a wrapper function for `libc::getgrouplist`.
+    ///
+    /// From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html
+    /// > If the number of groups of which user is a member is less than or
+    /// > equal to *ngroups, then the value *ngroups is returned.
+    /// > If the user is a member of more than *ngroups groups, then
+    /// > getgrouplist() returns -1.  In this case, the value returned in
+    /// > *ngroups can be used to resize the buffer passed to a further
+    /// > call getgrouplist().
+    ///
+    /// However, on macOS/darwin (and maybe others?) `getgrouplist` does
+    /// not update `ngroups` if `ngroups` is too small. Therefore, if not
+    /// updated by `getgrouplist`, `ngroups` needs to be increased in a
+    /// loop until `getgrouplist` stops returning -1.
+    pub fn belongs_to(&self) -> Vec<gid_t> {
+        let mut ngroups: c_int = 8;
+        let mut ngroups_old: c_int;
+        let mut groups = Vec::with_capacity(ngroups as usize);
+        let gid = self.inner.pw_gid;
+        let name = self.inner.pw_name;
+        loop {
+            ngroups_old = ngroups;
+            if unsafe { getgrouplist(name, gid, groups.as_mut_ptr(), &mut ngroups) } == -1 {
+                if ngroups == ngroups_old {
+                    ngroups *= 2;
+                }
+                groups.resize(ngroups as usize, 0);
+            } else {
+                break;
+            }
+        }
+        unsafe {
+            groups.set_len(ngroups as usize);
+        }
+        groups.truncate(ngroups as usize);
+        groups
+    }
+}
+
+pub struct Group {
+    inner: group,
+}
+
+impl Group {
+    /// AKA group.gr_name
+    pub fn name(&self) -> Cow<str> {
+        cstr2cow!(self.inner.gr_name)
+    }
+
+    /// AKA group.gr_gid
+    pub fn gid(&self) -> gid_t {
+        self.inner.gr_gid
+    }
+
+    pub fn as_inner(&self) -> &group {
+        &self.inner
+    }
+
+    pub fn into_inner(self) -> group {
+        self.inner
+    }
+}
+
+/// Fetch desired entry.
+pub trait Locate<K> {
+    fn locate(key: K) -> IOResult<Self>
+    where
+        Self: ::std::marker::Sized;
+}
+
+macro_rules! f {
+    ($fnam:ident, $fid:ident, $t:ident, $st:ident) => {
+        impl Locate<$t> for $st {
+            fn locate(k: $t) -> IOResult<Self> {
+                unsafe {
+                    let data = $fid(k);
+                    if !data.is_null() {
+                        Ok($st {
+                            inner: ptr::read(data as *const _),
+                        })
+                    } else {
+                        Err(IOError::new(
+                            ErrorKind::NotFound,
+                            format!("No such id: {}", k),
+                        ))
+                    }
+                }
+            }
+        }
+
+        impl<'a> Locate<&'a str> for $st {
+            fn locate(k: &'a str) -> IOResult<Self> {
+                if let Ok(id) = k.parse::<$t>() {
+                    let data = unsafe { $fid(id) };
+                    if !data.is_null() {
+                        Ok($st {
+                            inner: unsafe { ptr::read(data as *const _) },
+                        })
+                    } else {
+                        Err(IOError::new(
+                            ErrorKind::NotFound,
+                            format!("No such id: {}", id),
+                        ))
+                    }
+                } else {
+                    unsafe {
+                        let data = $fnam(CString::new(k).unwrap().as_ptr());
+                        if !data.is_null() {
+                            Ok($st {
+                                inner: ptr::read(data as *const _),
+                            })
+                        } else {
+                            Err(IOError::new(
+                                ErrorKind::NotFound,
+                                format!("Not found: {}", k),
+                            ))
+                        }
+                    }
+                }
+            }
+        }
+    };
+}
+
+f!(getpwnam, getpwuid, uid_t, Passwd);
+#[cfg(not(target_os = "redox"))]
+f!(getgrnam, getgrgid, gid_t, Group);
+
+#[inline]
+pub fn uid2usr(id: uid_t) -> IOResult<String> {
+    Passwd::locate(id).map(|p| p.name().into_owned())
+}
+
+#[cfg(not(target_os = "redox"))]
+#[inline]
+pub fn gid2grp(id: gid_t) -> IOResult<String> {
+    Group::locate(id).map(|p| p.name().into_owned())
+}
+
+#[inline]
+pub fn usr2uid(name: &str) -> IOResult<uid_t> {
+    Passwd::locate(name).map(|p| p.uid())
+}
+
+#[cfg(not(target_os = "redox"))]
+#[inline]
+pub fn grp2gid(name: &str) -> IOResult<gid_t> {
+    Group::locate(name).map(|p| p.gid())
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn test_sort_groups() {
+        assert_eq!(sort_groups(vec![1, 2, 3], 4), vec![4, 1, 2, 3]);
+        assert_eq!(sort_groups(vec![1, 2, 3], 3), vec![3, 1, 2]);
+        assert_eq!(sort_groups(vec![1, 2, 3], 2), vec![2, 1, 3]);
+        assert_eq!(sort_groups(vec![1, 2, 3], 1), vec![1, 2, 3]);
+        assert_eq!(sort_groups(vec![1, 2, 3], 0), vec![0, 1, 2, 3]);
+    }
+
+    #[test]
+    fn test_entries_get_groups_gnu() {
+        if let Ok(mut groups) = get_groups() {
+            if let Some(last) = groups.pop() {
+                groups.insert(0, last);
+                assert_eq!(get_groups_gnu(Some(last)).unwrap(), groups);
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/fs.rs.html b/src/uucore/features/fs.rs.html new file mode 100644 index 000000000..8a67b572f --- /dev/null +++ b/src/uucore/features/fs.rs.html @@ -0,0 +1,885 @@ +fs.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Joseph Crail <jbcrail@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+#[cfg(unix)]
+use libc::{
+    mode_t, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRGRP,
+    S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH,
+    S_IXUSR,
+};
+use std::borrow::Cow;
+use std::env;
+use std::fs;
+use std::io::Result as IOResult;
+use std::io::{Error, ErrorKind};
+#[cfg(any(unix, target_os = "redox"))]
+use std::os::unix::fs::MetadataExt;
+use std::path::{Component, Path, PathBuf};
+
+#[cfg(unix)]
+#[macro_export]
+macro_rules! has {
+    ($mode:expr, $perm:expr) => {
+        $mode & $perm != 0
+    };
+}
+
+pub fn resolve_relative_path(path: &Path) -> Cow<Path> {
+    if path.components().all(|e| e != Component::ParentDir) {
+        return path.into();
+    }
+    let root = Component::RootDir.as_os_str();
+    let mut result = env::current_dir().unwrap_or_else(|_| PathBuf::from(root));
+    for comp in path.components() {
+        match comp {
+            Component::ParentDir => {
+                if let Ok(p) = result.read_link() {
+                    result = p;
+                }
+                result.pop();
+            }
+            Component::CurDir => (),
+            Component::RootDir | Component::Normal(_) | Component::Prefix(_) => {
+                result.push(comp.as_os_str())
+            }
+        }
+    }
+    result.into()
+}
+
+/// Controls how symbolic links should be handled when canonicalizing a path.
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum MissingHandling {
+    /// Return an error if any part of the path is missing.
+    Normal,
+
+    /// Resolve symbolic links, ignoring errors on the final component.
+    Existing,
+
+    /// Resolve symbolic links, ignoring errors on the non-final components.
+    Missing,
+}
+
+/// Controls when symbolic links are resolved
+#[derive(Clone, Copy, Debug, Eq, PartialEq)]
+pub enum ResolveMode {
+    /// Do not resolve any symbolic links.
+    None,
+
+    /// Resolve symlinks as encountered when processing the path
+    Physical,
+
+    /// Resolve '..' elements before symlinks
+    Logical,
+}
+
+// copied from https://github.com/rust-lang/cargo/blob/2e4cfc2b7d43328b207879228a2ca7d427d188bb/src/cargo/util/paths.rs#L65-L90
+// both projects are MIT https://github.com/rust-lang/cargo/blob/master/LICENSE-MIT
+// for std impl progress see rfc https://github.com/rust-lang/rfcs/issues/2208
+// replace this once that lands
+pub fn normalize_path(path: &Path) -> PathBuf {
+    let mut components = path.components().peekable();
+    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
+        components.next();
+        PathBuf::from(c.as_os_str())
+    } else {
+        PathBuf::new()
+    };
+
+    for component in components {
+        match component {
+            Component::Prefix(..) => unreachable!(),
+            Component::RootDir => {
+                ret.push(component.as_os_str());
+            }
+            Component::CurDir => {}
+            Component::ParentDir => {
+                ret.pop();
+            }
+            Component::Normal(c) => {
+                ret.push(c);
+            }
+        }
+    }
+    ret
+}
+
+fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
+    const MAX_LINKS_FOLLOWED: u32 = 255;
+    let mut followed = 0;
+    let mut result = original.as_ref().to_path_buf();
+    loop {
+        if followed == MAX_LINKS_FOLLOWED {
+            return Err(Error::new(
+                ErrorKind::InvalidInput,
+                "maximum links followed",
+            ));
+        }
+
+        if !fs::symlink_metadata(&result)?.file_type().is_symlink() {
+            break;
+        }
+
+        followed += 1;
+        let path = fs::read_link(&result)?;
+        result.pop();
+        result.push(path);
+    }
+    Ok(result)
+}
+
+/// Return the canonical, absolute form of a path.
+///
+/// This function is a generalization of [`std::fs::canonicalize`] that
+/// allows controlling how symbolic links are resolved and how to deal
+/// with missing components. It returns the canonical, absolute form of
+/// a path.
+/// The `miss_mode` parameter controls how missing path elements are handled
+///
+/// * [`MissingHandling::Normal`] makes this function behave like
+///   [`std::fs::canonicalize`], resolving symbolic links and returning
+///   an error if the path does not exist.
+/// * [`MissingHandling::Missing`] makes this function ignore non-final
+///   components of the path that could not be resolved.
+/// * [`MissingHandling::Existing`] makes this function return an error
+///   if the final component of the path does not exist.
+///
+/// The `res_mode` parameter controls how symbolic links are
+/// resolved:
+///
+/// * [`ResolveMode::None`] makes this function not try to resolve
+///   any symbolic links.
+/// * [`ResolveMode::Physical`] makes this function resolve symlinks as they
+///   are encountered
+/// * [`ResolveMode::Logical`] makes this function resolve '..' components
+///   before symlinks
+///
+pub fn canonicalize<P: AsRef<Path>>(
+    original: P,
+    miss_mode: MissingHandling,
+    res_mode: ResolveMode,
+) -> IOResult<PathBuf> {
+    // Create an absolute path
+    let original = original.as_ref();
+    let original = if original.is_absolute() {
+        original.to_path_buf()
+    } else {
+        dunce::canonicalize(env::current_dir().unwrap())
+            .unwrap()
+            .join(original)
+    };
+
+    let mut result = PathBuf::new();
+    let mut parts = vec![];
+
+    // Split path by directory separator; add prefix (Windows-only) and root
+    // directory to final path buffer; add remaining parts to temporary
+    // vector for canonicalization.
+    for part in original.components() {
+        match part {
+            Component::Prefix(_) | Component::RootDir => {
+                result.push(part.as_os_str());
+            }
+            Component::CurDir => (),
+            Component::ParentDir => {
+                if res_mode == ResolveMode::Logical {
+                    parts.pop();
+                } else {
+                    parts.push(part.as_os_str());
+                }
+            }
+            Component::Normal(_) => {
+                parts.push(part.as_os_str());
+            }
+        }
+    }
+
+    // Resolve the symlinks where possible
+    if !parts.is_empty() {
+        for part in parts[..parts.len() - 1].iter() {
+            result.push(part);
+
+            //resolve as we go to handle long relative paths on windows
+            if res_mode == ResolveMode::Physical {
+                result = normalize_path(&result);
+            }
+
+            if res_mode == ResolveMode::None {
+                continue;
+            }
+
+            match resolve(&result) {
+                Err(_) if miss_mode == MissingHandling::Missing => continue,
+                Err(e) => return Err(e),
+                Ok(path) => {
+                    result.pop();
+                    result.push(path);
+                }
+            }
+        }
+
+        result.push(parts.last().unwrap());
+
+        if res_mode == ResolveMode::None {
+            return Ok(result);
+        }
+
+        match resolve(&result) {
+            Err(e) if miss_mode == MissingHandling::Existing => {
+                return Err(e);
+            }
+            Ok(path) => {
+                result.pop();
+                result.push(path);
+            }
+            Err(_) => (),
+        }
+        if res_mode == ResolveMode::Physical {
+            result = normalize_path(&result);
+        }
+    }
+    Ok(result)
+}
+
+#[cfg(not(unix))]
+#[allow(unused_variables)]
+pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> String {
+    if display_file_type {
+        return String::from("----------");
+    }
+    String::from("---------")
+}
+
+#[cfg(unix)]
+pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> String {
+    let mode: mode_t = metadata.mode() as mode_t;
+    display_permissions_unix(mode, display_file_type)
+}
+
+#[cfg(unix)]
+pub fn display_permissions_unix(mode: mode_t, display_file_type: bool) -> String {
+    let mut result;
+    if display_file_type {
+        result = String::with_capacity(10);
+        result.push(match mode & S_IFMT {
+            S_IFDIR => 'd',
+            S_IFCHR => 'c',
+            S_IFBLK => 'b',
+            S_IFREG => '-',
+            S_IFIFO => 'p',
+            S_IFLNK => 'l',
+            S_IFSOCK => 's',
+            // TODO: Other file types
+            _ => '?',
+        });
+    } else {
+        result = String::with_capacity(9);
+    }
+
+    result.push(if has!(mode, S_IRUSR) { 'r' } else { '-' });
+    result.push(if has!(mode, S_IWUSR) { 'w' } else { '-' });
+    result.push(if has!(mode, S_ISUID as mode_t) {
+        if has!(mode, S_IXUSR) {
+            's'
+        } else {
+            'S'
+        }
+    } else if has!(mode, S_IXUSR) {
+        'x'
+    } else {
+        '-'
+    });
+
+    result.push(if has!(mode, S_IRGRP) { 'r' } else { '-' });
+    result.push(if has!(mode, S_IWGRP) { 'w' } else { '-' });
+    result.push(if has!(mode, S_ISGID as mode_t) {
+        if has!(mode, S_IXGRP) {
+            's'
+        } else {
+            'S'
+        }
+    } else if has!(mode, S_IXGRP) {
+        'x'
+    } else {
+        '-'
+    });
+
+    result.push(if has!(mode, S_IROTH) { 'r' } else { '-' });
+    result.push(if has!(mode, S_IWOTH) { 'w' } else { '-' });
+    result.push(if has!(mode, S_ISVTX as mode_t) {
+        if has!(mode, S_IXOTH) {
+            't'
+        } else {
+            'T'
+        }
+    } else if has!(mode, S_IXOTH) {
+        'x'
+    } else {
+        '-'
+    });
+
+    result
+}
+
+#[cfg(test)]
+mod tests {
+    // Note this useful idiom: importing names from outer (for mod tests) scope.
+    use super::*;
+
+    struct NormalizePathTestCase<'a> {
+        path: &'a str,
+        test: &'a str,
+    }
+
+    const NORMALIZE_PATH_TESTS: [NormalizePathTestCase; 8] = [
+        NormalizePathTestCase {
+            path: "./foo/bar.txt",
+            test: "foo/bar.txt",
+        },
+        NormalizePathTestCase {
+            path: "bar/../foo/bar.txt",
+            test: "foo/bar.txt",
+        },
+        NormalizePathTestCase {
+            path: "foo///bar.txt",
+            test: "foo/bar.txt",
+        },
+        NormalizePathTestCase {
+            path: "foo///bar",
+            test: "foo/bar",
+        },
+        NormalizePathTestCase {
+            path: "foo//./bar",
+            test: "foo/bar",
+        },
+        NormalizePathTestCase {
+            path: "/foo//./bar",
+            test: "/foo/bar",
+        },
+        NormalizePathTestCase {
+            path: r"C:/you/later/",
+            test: "C:/you/later",
+        },
+        NormalizePathTestCase {
+            path: "\\networkShare/a//foo//./bar",
+            test: "\\networkShare/a/foo/bar",
+        },
+    ];
+
+    #[test]
+    fn test_normalize_path() {
+        for test in NORMALIZE_PATH_TESTS.iter() {
+            let path = Path::new(test.path);
+            let normalized = normalize_path(path);
+            assert_eq!(
+                test.test
+                    .replace("/", std::path::MAIN_SEPARATOR.to_string().as_str()),
+                normalized.to_str().expect("Path is not valid utf-8!")
+            );
+        }
+    }
+
+    #[cfg(unix)]
+    #[test]
+    fn test_display_permissions() {
+        // spell-checker:ignore (perms) brwsr drwxr rwxr
+        assert_eq!(
+            "drwxr-xr-x",
+            display_permissions_unix(S_IFDIR | 0o755, true)
+        );
+        assert_eq!(
+            "rwxr-xr-x",
+            display_permissions_unix(S_IFDIR | 0o755, false)
+        );
+        assert_eq!(
+            "-rw-r--r--",
+            display_permissions_unix(S_IFREG | 0o644, true)
+        );
+        assert_eq!(
+            "srw-r-----",
+            display_permissions_unix(S_IFSOCK | 0o640, true)
+        );
+        assert_eq!(
+            "lrw-r-xr-x",
+            display_permissions_unix(S_IFLNK | 0o655, true)
+        );
+        assert_eq!("?rw-r-xr-x", display_permissions_unix(0o655, true));
+
+        assert_eq!(
+            "brwSr-xr-x",
+            display_permissions_unix(S_IFBLK | S_ISUID as mode_t | 0o655, true)
+        );
+        assert_eq!(
+            "brwsr-xr-x",
+            display_permissions_unix(S_IFBLK | S_ISUID as mode_t | 0o755, true)
+        );
+
+        assert_eq!(
+            "prw---sr--",
+            display_permissions_unix(S_IFIFO | S_ISGID as mode_t | 0o614, true)
+        );
+        assert_eq!(
+            "prw---Sr--",
+            display_permissions_unix(S_IFIFO | S_ISGID as mode_t | 0o604, true)
+        );
+
+        assert_eq!(
+            "c---r-xr-t",
+            display_permissions_unix(S_IFCHR | S_ISVTX as mode_t | 0o055, true)
+        );
+        assert_eq!(
+            "c---r-xr-T",
+            display_permissions_unix(S_IFCHR | S_ISVTX as mode_t | 0o054, true)
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/fsext.rs.html b/src/uucore/features/fsext.rs.html new file mode 100644 index 000000000..e9072c63e --- /dev/null +++ b/src/uucore/features/fsext.rs.html @@ -0,0 +1,1715 @@ +fsext.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+// (c) Fangxu Hu <framlog@gmail.com>
+// (c) Sylvestre Ledru <sylvestre@debian.org>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (arch) bitrig ; (fs) cifs smbfs
+
+extern crate time;
+
+pub use crate::*; // import macros from `../../macros.rs`
+
+#[cfg(target_os = "linux")]
+const LINUX_MTAB: &str = "/etc/mtab";
+#[cfg(target_os = "linux")]
+const LINUX_MOUNTINFO: &str = "/proc/self/mountinfo";
+static MOUNT_OPT_BIND: &str = "bind";
+#[cfg(windows)]
+const MAX_PATH: usize = 266;
+#[cfg(not(unix))]
+static EXIT_ERR: i32 = 1;
+
+#[cfg(windows)]
+use std::ffi::OsString;
+#[cfg(windows)]
+use std::os::windows::ffi::OsStrExt;
+#[cfg(windows)]
+use std::os::windows::ffi::OsStringExt;
+#[cfg(windows)]
+use winapi::shared::minwindef::DWORD;
+#[cfg(windows)]
+use winapi::um::errhandlingapi::GetLastError;
+#[cfg(windows)]
+use winapi::um::fileapi::GetDiskFreeSpaceW;
+#[cfg(windows)]
+use winapi::um::fileapi::{
+    FindFirstVolumeW, FindNextVolumeW, FindVolumeClose, GetDriveTypeW, GetVolumeInformationW,
+    GetVolumePathNamesForVolumeNameW, QueryDosDeviceW,
+};
+#[cfg(windows)]
+use winapi::um::handleapi::INVALID_HANDLE_VALUE;
+#[cfg(windows)]
+use winapi::um::winbase::DRIVE_REMOTE;
+
+#[cfg(windows)]
+macro_rules! String2LPWSTR {
+    ($str: expr) => {
+        OsString::from($str.clone())
+            .as_os_str()
+            .encode_wide()
+            .chain(Some(0))
+            .collect::<Vec<u16>>()
+            .as_ptr()
+    };
+}
+
+#[cfg(windows)]
+#[allow(non_snake_case)]
+fn LPWSTR2String(buf: &[u16]) -> String {
+    let len = unsafe { libc::wcslen(buf.as_ptr()) };
+    OsString::from_wide(&buf[..len as usize])
+        .into_string()
+        .unwrap()
+}
+
+use self::time::Timespec;
+#[cfg(unix)]
+use libc::{
+    mode_t, strerror, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK,
+};
+use std::borrow::Cow;
+use std::convert::{AsRef, From};
+#[cfg(unix)]
+use std::ffi::CString;
+#[cfg(unix)]
+use std::io::Error as IOError;
+#[cfg(unix)]
+use std::mem;
+use std::path::Path;
+use std::time::UNIX_EPOCH;
+
+#[cfg(any(
+    target_os = "linux",
+    target_vendor = "apple",
+    target_os = "android",
+    target_os = "freebsd"
+))]
+pub use libc::statfs as StatFs;
+#[cfg(any(
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "openbsd",
+    target_os = "bitrig",
+    target_os = "dragonfly",
+    target_os = "redox"
+))]
+pub use libc::statvfs as StatFs;
+
+#[cfg(any(
+    target_os = "linux",
+    target_vendor = "apple",
+    target_os = "android",
+    target_os = "freebsd"
+))]
+pub use libc::statfs as statfs_fn;
+#[cfg(any(
+    target_os = "openbsd",
+    target_os = "netbsd",
+    target_os = "openbsd",
+    target_os = "bitrig",
+    target_os = "dragonfly",
+    target_os = "redox"
+))]
+pub use libc::statvfs as statfs_fn;
+
+pub trait BirthTime {
+    fn pretty_birth(&self) -> String;
+    fn birth(&self) -> String;
+}
+
+use std::fs::Metadata;
+impl BirthTime for Metadata {
+    fn pretty_birth(&self) -> String {
+        self.created()
+            .ok()
+            .and_then(|t| t.duration_since(UNIX_EPOCH).ok())
+            .map(|e| pretty_time(e.as_secs() as i64, i64::from(e.subsec_nanos())))
+            .unwrap_or_else(|| "-".to_owned())
+    }
+
+    fn birth(&self) -> String {
+        self.created()
+            .ok()
+            .and_then(|t| t.duration_since(UNIX_EPOCH).ok())
+            .map(|e| format!("{}", e.as_secs()))
+            .unwrap_or_else(|| "0".to_owned())
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct MountInfo {
+    // it stores `volume_name` in windows platform and `dev_id` in unix platform
+    pub dev_id: String,
+    pub dev_name: String,
+    pub fs_type: String,
+    pub mount_dir: String,
+    pub mount_option: String, // we only care "bind" option
+    pub mount_root: String,
+    pub remote: bool,
+    pub dummy: bool,
+}
+
+impl MountInfo {
+    fn set_missing_fields(&mut self) {
+        #[cfg(unix)]
+        {
+            // We want to keep the dev_id on Windows
+            // but set dev_id
+            let path = CString::new(self.mount_dir.clone()).unwrap();
+            unsafe {
+                let mut stat = mem::zeroed();
+                if libc::stat(path.as_ptr(), &mut stat) == 0 {
+                    self.dev_id = (stat.st_dev as i32).to_string();
+                } else {
+                    self.dev_id = "".to_string();
+                }
+            }
+        }
+        // set MountInfo::dummy
+        // spell-checker:disable
+        match self.fs_type.as_ref() {
+            "autofs" | "proc" | "subfs"
+            /* for Linux 2.6/3.x */
+            | "debugfs" | "devpts" | "fusectl" | "mqueue" | "rpc_pipefs" | "sysfs"
+            /* FreeBSD, Linux 2.4 */
+            | "devfs"
+            /* for NetBSD 3.0 */
+            | "kernfs"
+            /* for Irix 6.5 */
+            | "ignore" => self.dummy = true,
+            _ => self.dummy = self.fs_type == "none"
+                && !self.mount_option.contains(MOUNT_OPT_BIND)
+        }
+        // spell-checker:enable
+        // set MountInfo::remote
+        #[cfg(windows)]
+        {
+            self.remote = DRIVE_REMOTE == unsafe { GetDriveTypeW(String2LPWSTR!(self.mount_root)) };
+        }
+        #[cfg(unix)]
+        {
+            if self.dev_name.find(':').is_some()
+                || (self.dev_name.starts_with("//") && self.fs_type == "smbfs"
+                    || self.fs_type == "cifs")
+                || self.dev_name == "-hosts"
+            {
+                self.remote = true;
+            } else {
+                self.remote = false;
+            }
+        }
+    }
+
+    #[cfg(target_os = "linux")]
+    fn new(file_name: &str, raw: Vec<&str>) -> Option<MountInfo> {
+        match file_name {
+            // spell-checker:ignore (word) noatime
+            // Format: 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+            // "man proc" for more details
+            LINUX_MOUNTINFO => {
+                let mut m = MountInfo {
+                    dev_id: "".to_string(),
+                    dev_name: raw[9].to_string(),
+                    fs_type: raw[8].to_string(),
+                    mount_root: raw[3].to_string(),
+                    mount_dir: raw[4].to_string(),
+                    mount_option: raw[5].to_string(),
+                    remote: false,
+                    dummy: false,
+                };
+                m.set_missing_fields();
+                Some(m)
+            }
+            LINUX_MTAB => {
+                let mut m = MountInfo {
+                    dev_id: "".to_string(),
+                    dev_name: raw[0].to_string(),
+                    fs_type: raw[2].to_string(),
+                    mount_root: "".to_string(),
+                    mount_dir: raw[1].to_string(),
+                    mount_option: raw[3].to_string(),
+                    remote: false,
+                    dummy: false,
+                };
+                m.set_missing_fields();
+                Some(m)
+            }
+            _ => None,
+        }
+    }
+    #[cfg(windows)]
+    fn new(mut volume_name: String) -> Option<MountInfo> {
+        let mut dev_name_buf = [0u16; MAX_PATH];
+        volume_name.pop();
+        unsafe {
+            QueryDosDeviceW(
+                OsString::from(volume_name.clone())
+                    .as_os_str()
+                    .encode_wide()
+                    .chain(Some(0))
+                    .skip(4)
+                    .collect::<Vec<u16>>()
+                    .as_ptr(),
+                dev_name_buf.as_mut_ptr(),
+                dev_name_buf.len() as DWORD,
+            )
+        };
+        volume_name.push('\\');
+        let dev_name = LPWSTR2String(&dev_name_buf);
+
+        let mut mount_root_buf = [0u16; MAX_PATH];
+        let success = unsafe {
+            GetVolumePathNamesForVolumeNameW(
+                String2LPWSTR!(volume_name),
+                mount_root_buf.as_mut_ptr(),
+                mount_root_buf.len() as DWORD,
+                ptr::null_mut(),
+            )
+        };
+        if 0 == success {
+            // TODO: support the case when `GetLastError()` returns `ERROR_MORE_DATA`
+            return None;
+        }
+        let mount_root = LPWSTR2String(&mount_root_buf);
+
+        let mut fs_type_buf = [0u16; MAX_PATH];
+        let success = unsafe {
+            GetVolumeInformationW(
+                String2LPWSTR!(mount_root),
+                ptr::null_mut(),
+                0,
+                ptr::null_mut(),
+                ptr::null_mut(),
+                ptr::null_mut(),
+                fs_type_buf.as_mut_ptr(),
+                fs_type_buf.len() as DWORD,
+            )
+        };
+        let fs_type = if 0 != success {
+            Some(LPWSTR2String(&fs_type_buf))
+        } else {
+            None
+        };
+        let mut mn_info = MountInfo {
+            dev_id: volume_name,
+            dev_name,
+            fs_type: fs_type.unwrap_or_else(|| "".to_string()),
+            mount_root,
+            mount_dir: "".to_string(),
+            mount_option: "".to_string(),
+            remote: false,
+            dummy: false,
+        };
+        mn_info.set_missing_fields();
+        Some(mn_info)
+    }
+}
+
+#[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "netbsd"))]
+use std::ffi::CStr;
+#[cfg(any(target_os = "freebsd", target_vendor = "apple", target_os = "netbsd"))]
+impl From<StatFs> for MountInfo {
+    fn from(statfs: StatFs) -> Self {
+        let mut info = MountInfo {
+            dev_id: "".to_string(),
+            dev_name: unsafe {
+                // spell-checker:disable-next-line
+                CStr::from_ptr(&statfs.f_mntfromname[0])
+                    .to_string_lossy()
+                    .into_owned()
+            },
+            fs_type: unsafe {
+                // spell-checker:disable-next-line
+                CStr::from_ptr(&statfs.f_fstypename[0])
+                    .to_string_lossy()
+                    .into_owned()
+            },
+            mount_dir: unsafe {
+                // spell-checker:disable-next-line
+                CStr::from_ptr(&statfs.f_mntonname[0])
+                    .to_string_lossy()
+                    .into_owned()
+            },
+            mount_root: "".to_string(),
+            mount_option: "".to_string(),
+            remote: false,
+            dummy: false,
+        };
+        info.set_missing_fields();
+        info
+    }
+}
+
+#[cfg(any(target_os = "freebsd", target_vendor = "apple", target_os = "netbsd"))]
+use libc::c_int;
+#[cfg(any(target_os = "freebsd", target_vendor = "apple", target_os = "netbsd"))]
+extern "C" {
+    #[cfg(all(target_vendor = "apple", target_arch = "x86_64"))]
+    #[link_name = "getmntinfo$INODE64"] // spell-checker:disable-line
+    fn get_mount_info(mount_buffer_p: *mut *mut StatFs, flags: c_int) -> c_int;
+
+    #[cfg(any(
+        all(target_os = "freebsd"),
+        all(target_os = "netbsd"),
+        all(target_vendor = "apple", target_arch = "aarch64")
+    ))]
+    #[link_name = "getmntinfo"] // spell-checker:disable-line
+    fn get_mount_info(mount_buffer_p: *mut *mut StatFs, flags: c_int) -> c_int;
+}
+
+#[cfg(target_os = "linux")]
+use std::fs::File;
+#[cfg(target_os = "linux")]
+use std::io::{BufRead, BufReader};
+#[cfg(any(
+    target_vendor = "apple",
+    target_os = "freebsd",
+    target_os = "windows",
+    target_os = "netbsd"
+))]
+use std::ptr;
+#[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "netbsd"))]
+use std::slice;
+/// Read file system list.
+pub fn read_fs_list() -> Vec<MountInfo> {
+    #[cfg(target_os = "linux")]
+    {
+        let (file_name, f) = File::open(LINUX_MOUNTINFO)
+            .map(|f| (LINUX_MOUNTINFO, f))
+            .or_else(|_| File::open(LINUX_MTAB).map(|f| (LINUX_MTAB, f)))
+            .expect("failed to find mount list files");
+        let reader = BufReader::new(f);
+        reader
+            .lines()
+            .filter_map(|line| line.ok())
+            .filter_map(|line| {
+                let raw_data = line.split_whitespace().collect::<Vec<&str>>();
+                MountInfo::new(file_name, raw_data)
+            })
+            .collect::<Vec<_>>()
+    }
+    #[cfg(any(target_os = "freebsd", target_vendor = "apple", target_os = "netbsd"))]
+    {
+        let mut mount_buffer_ptr: *mut StatFs = ptr::null_mut();
+        let len = unsafe { get_mount_info(&mut mount_buffer_ptr, 1_i32) };
+        if len < 0 {
+            crash!(1, "get_mount_info() failed");
+        }
+        let mounts = unsafe { slice::from_raw_parts(mount_buffer_ptr, len as usize) };
+        mounts
+            .iter()
+            .map(|m| MountInfo::from(*m))
+            .collect::<Vec<_>>()
+    }
+    #[cfg(windows)]
+    {
+        let mut volume_name_buf = [0u16; MAX_PATH];
+        // As recommended in the MS documentation, retrieve the first volume before the others
+        let find_handle = unsafe {
+            FindFirstVolumeW(volume_name_buf.as_mut_ptr(), volume_name_buf.len() as DWORD)
+        };
+        if INVALID_HANDLE_VALUE == find_handle {
+            crash!(EXIT_ERR, "FindFirstVolumeW failed: {}", unsafe {
+                GetLastError()
+            });
+        }
+        let mut mounts = Vec::<MountInfo>::new();
+        loop {
+            let volume_name = LPWSTR2String(&volume_name_buf);
+            if !volume_name.starts_with("\\\\?\\") || !volume_name.ends_with('\\') {
+                show_warning!("A bad path was skipped: {}", volume_name);
+                continue;
+            }
+            if let Some(m) = MountInfo::new(volume_name) {
+                mounts.push(m);
+            }
+            if 0 == unsafe {
+                FindNextVolumeW(
+                    find_handle,
+                    volume_name_buf.as_mut_ptr(),
+                    volume_name_buf.len() as DWORD,
+                )
+            } {
+                let err = unsafe { GetLastError() };
+                if err != winapi::shared::winerror::ERROR_NO_MORE_FILES {
+                    crash!(EXIT_ERR, "FindNextVolumeW failed: {}", err);
+                }
+                break;
+            }
+        }
+        unsafe {
+            FindVolumeClose(find_handle);
+        }
+        mounts
+    }
+    #[cfg(target_os = "redox")]
+    {
+        // No method to read mounts, yet
+        Vec::new()
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct FsUsage {
+    pub blocksize: u64,
+    pub blocks: u64,
+    pub bfree: u64,
+    pub bavail: u64,
+    pub bavail_top_bit_set: bool,
+    pub files: u64,
+    pub ffree: u64,
+}
+
+impl FsUsage {
+    #[cfg(unix)]
+    pub fn new(statvfs: StatFs) -> FsUsage {
+        {
+            FsUsage {
+                blocksize: statvfs.f_bsize as u64, // or `statvfs.f_frsize` ?
+                blocks: statvfs.f_blocks as u64,
+                bfree: statvfs.f_bfree as u64,
+                bavail: statvfs.f_bavail as u64,
+                bavail_top_bit_set: ((statvfs.f_bavail as u64) & (1u64.rotate_right(1))) != 0,
+                files: statvfs.f_files as u64,
+                ffree: statvfs.f_ffree as u64,
+            }
+        }
+    }
+    #[cfg(not(unix))]
+    pub fn new(path: &Path) -> FsUsage {
+        let mut root_path = [0u16; MAX_PATH];
+        let success = unsafe {
+            GetVolumePathNamesForVolumeNameW(
+                //path_utf8.as_ptr(),
+                String2LPWSTR!(path.as_os_str()),
+                root_path.as_mut_ptr(),
+                root_path.len() as DWORD,
+                ptr::null_mut(),
+            )
+        };
+        if 0 == success {
+            crash!(
+                EXIT_ERR,
+                "GetVolumePathNamesForVolumeNameW failed: {}",
+                unsafe { GetLastError() }
+            );
+        }
+
+        let mut sectors_per_cluster = 0;
+        let mut bytes_per_sector = 0;
+        let mut number_of_free_clusters = 0;
+        let mut total_number_of_clusters = 0;
+
+        let success = unsafe {
+            GetDiskFreeSpaceW(
+                String2LPWSTR!(path.as_os_str()),
+                &mut sectors_per_cluster,
+                &mut bytes_per_sector,
+                &mut number_of_free_clusters,
+                &mut total_number_of_clusters,
+            )
+        };
+        if 0 == success {
+            // Fails in case of CD for example
+            //crash!(EXIT_ERR, "GetDiskFreeSpaceW failed: {}", unsafe {
+            //GetLastError()
+            //});
+        }
+
+        let bytes_per_cluster = sectors_per_cluster as u64 * bytes_per_sector as u64;
+        FsUsage {
+            // f_bsize      File system block size.
+            blocksize: bytes_per_cluster as u64,
+            // f_blocks - Total number of blocks on the file system, in units of f_frsize.
+            // frsize =     Fundamental file system block size (fragment size).
+            blocks: total_number_of_clusters as u64,
+            //  Total number of free blocks.
+            bfree: number_of_free_clusters as u64,
+            //  Total number of free blocks available to non-privileged processes.
+            bavail: 0,
+            bavail_top_bit_set: ((bytes_per_sector as u64) & (1u64.rotate_right(1))) != 0,
+            // Total number of file nodes (inodes) on the file system.
+            files: 0, // Not available on windows
+            // Total number of free file nodes (inodes).
+            ffree: 4096, // Meaningless on Windows
+        }
+    }
+}
+
+#[cfg(unix)]
+pub trait FsMeta {
+    fn fs_type(&self) -> i64;
+    fn io_size(&self) -> u64;
+    fn block_size(&self) -> i64;
+    fn total_blocks(&self) -> u64;
+    fn free_blocks(&self) -> u64;
+    fn avail_blocks(&self) -> u64;
+    fn total_file_nodes(&self) -> u64;
+    fn free_file_nodes(&self) -> u64;
+    fn fsid(&self) -> u64;
+    fn namelen(&self) -> u64;
+}
+
+#[cfg(unix)]
+impl FsMeta for StatFs {
+    fn block_size(&self) -> i64 {
+        self.f_bsize as i64
+    }
+    fn total_blocks(&self) -> u64 {
+        self.f_blocks as u64
+    }
+    fn free_blocks(&self) -> u64 {
+        self.f_bfree as u64
+    }
+    fn avail_blocks(&self) -> u64 {
+        self.f_bavail as u64
+    }
+    fn total_file_nodes(&self) -> u64 {
+        self.f_files as u64
+    }
+    fn free_file_nodes(&self) -> u64 {
+        self.f_ffree as u64
+    }
+    #[cfg(any(target_os = "linux", target_vendor = "apple", target_os = "freebsd"))]
+    fn fs_type(&self) -> i64 {
+        self.f_type as i64
+    }
+    #[cfg(not(any(target_os = "linux", target_vendor = "apple", target_os = "freebsd")))]
+    fn fs_type(&self) -> i64 {
+        // FIXME: statvfs doesn't have an equivalent, so we need to do something else
+        unimplemented!()
+    }
+
+    #[cfg(target_os = "linux")]
+    fn io_size(&self) -> u64 {
+        self.f_frsize as u64
+    }
+    #[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "netbsd"))]
+    fn io_size(&self) -> u64 {
+        self.f_iosize as u64
+    }
+    // XXX: dunno if this is right
+    #[cfg(not(any(
+        target_vendor = "apple",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd"
+    )))]
+    fn io_size(&self) -> u64 {
+        self.f_bsize as u64
+    }
+
+    // Linux, SunOS, HP-UX, 4.4BSD, FreeBSD have a system call statfs() that returns
+    // a struct statfs, containing a fsid_t f_fsid, where fsid_t is defined
+    // as struct { int val[2];  }
+    //
+    // Solaris, Irix and POSIX have a system call statvfs(2) that returns a
+    // struct statvfs, containing an  unsigned  long  f_fsid
+    #[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "linux"))]
+    fn fsid(&self) -> u64 {
+        let f_fsid: &[u32; 2] =
+            unsafe { &*(&self.f_fsid as *const libc::fsid_t as *const [u32; 2]) };
+        (u64::from(f_fsid[0])) << 32 | u64::from(f_fsid[1])
+    }
+    #[cfg(not(any(target_vendor = "apple", target_os = "freebsd", target_os = "linux")))]
+    fn fsid(&self) -> u64 {
+        self.f_fsid as u64
+    }
+
+    #[cfg(target_os = "linux")]
+    fn namelen(&self) -> u64 {
+        self.f_namelen as u64
+    }
+    #[cfg(target_vendor = "apple")]
+    fn namelen(&self) -> u64 {
+        1024
+    }
+    #[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
+    fn namelen(&self) -> u64 {
+        self.f_namemax as u64 // spell-checker:disable-line
+    }
+    // XXX: should everything just use statvfs?
+    #[cfg(not(any(
+        target_vendor = "apple",
+        target_os = "freebsd",
+        target_os = "linux",
+        target_os = "netbsd"
+    )))]
+    fn namelen(&self) -> u64 {
+        self.f_namemax as u64 // spell-checker:disable-line
+    }
+}
+
+#[cfg(unix)]
+pub fn statfs<P: AsRef<Path>>(path: P) -> Result<StatFs, String>
+where
+    Vec<u8>: From<P>,
+{
+    match CString::new(path) {
+        Ok(p) => {
+            let mut buffer: StatFs = unsafe { mem::zeroed() };
+            unsafe {
+                match statfs_fn(p.as_ptr(), &mut buffer) {
+                    0 => Ok(buffer),
+                    _ => {
+                        let errno = IOError::last_os_error().raw_os_error().unwrap_or(0);
+                        Err(CString::from_raw(strerror(errno))
+                            .into_string()
+                            .unwrap_or_else(|_| "Unknown Error".to_owned()))
+                    }
+                }
+            }
+        }
+        Err(e) => Err(e.to_string()),
+    }
+}
+
+pub fn pretty_time(sec: i64, nsec: i64) -> String {
+    // sec == seconds since UNIX_EPOCH
+    // nsec == nanoseconds since (UNIX_EPOCH + sec)
+    let tm = time::at(Timespec::new(sec, nsec as i32));
+    let res = time::strftime("%Y-%m-%d %H:%M:%S.%f %z", &tm).unwrap();
+    if res.ends_with(" -0000") {
+        res.replace(" -0000", " +0000")
+    } else {
+        res
+    }
+}
+
+#[cfg(unix)]
+pub fn pretty_filetype<'a>(mode: mode_t, size: u64) -> &'a str {
+    match mode & S_IFMT {
+        S_IFREG => {
+            if size != 0 {
+                "regular file"
+            } else {
+                "regular empty file"
+            }
+        }
+        S_IFDIR => "directory",
+        S_IFLNK => "symbolic link",
+        S_IFCHR => "character special file",
+        S_IFBLK => "block special file",
+        S_IFIFO => "fifo",
+        S_IFSOCK => "socket",
+        // TODO: Other file types
+        // See coreutils/gnulib/lib/file-type.c // spell-checker:disable-line
+        _ => "weird file",
+    }
+}
+
+pub fn pretty_fstype<'a>(fstype: i64) -> Cow<'a, str> {
+    // spell-checker:disable
+    match fstype {
+        0x6163_6673 => "acfs".into(),
+        0xADF5 => "adfs".into(),
+        0xADFF => "affs".into(),
+        0x5346_414F => "afs".into(),
+        0x0904_1934 => "anon-inode FS".into(),
+        0x6175_6673 => "aufs".into(),
+        0x0187 => "autofs".into(),
+        0x4246_5331 => "befs".into(),
+        0x6264_6576 => "bdevfs".into(),
+        0x1BAD_FACE => "bfs".into(),
+        0xCAFE_4A11 => "bpf_fs".into(),
+        0x4249_4E4D => "binfmt_misc".into(),
+        0x9123_683E => "btrfs".into(),
+        0x7372_7279 => "btrfs_test".into(),
+        0x00C3_6400 => "ceph".into(),
+        0x0027_E0EB => "cgroupfs".into(),
+        0xFF53_4D42 => "cifs".into(),
+        0x7375_7245 => "coda".into(),
+        0x012F_F7B7 => "coh".into(),
+        0x6265_6570 => "configfs".into(),
+        0x28CD_3D45 => "cramfs".into(),
+        0x453D_CD28 => "cramfs-wend".into(),
+        0x6462_6720 => "debugfs".into(),
+        0x1373 => "devfs".into(),
+        0x1CD1 => "devpts".into(),
+        0xF15F => "ecryptfs".into(),
+        0xDE5E_81E4 => "efivarfs".into(),
+        0x0041_4A53 => "efs".into(),
+        0x5DF5 => "exofs".into(),
+        0x137D => "ext".into(),
+        0xEF53 => "ext2/ext3".into(),
+        0xEF51 => "ext2".into(),
+        0xF2F5_2010 => "f2fs".into(),
+        0x4006 => "fat".into(),
+        0x1983_0326 => "fhgfs".into(),
+        0x6573_5546 => "fuseblk".into(),
+        0x6573_5543 => "fusectl".into(),
+        0x0BAD_1DEA => "futexfs".into(),
+        0x0116_1970 => "gfs/gfs2".into(),
+        0x4750_4653 => "gpfs".into(),
+        0x4244 => "hfs".into(),
+        0x482B => "hfs+".into(),
+        0x4858 => "hfsx".into(),
+        0x00C0_FFEE => "hostfs".into(),
+        0xF995_E849 => "hpfs".into(),
+        0x9584_58F6 => "hugetlbfs".into(),
+        0x1130_7854 => "inodefs".into(),
+        0x0131_11A8 => "ibrix".into(),
+        0x2BAD_1DEA => "inotifyfs".into(),
+        0x9660 => "isofs".into(),
+        0x4004 => "isofs".into(),
+        0x4000 => "isofs".into(),
+        0x07C0 => "jffs".into(),
+        0x72B6 => "jffs2".into(),
+        0x3153_464A => "jfs".into(),
+        0x6B41_4653 => "k-afs".into(),
+        0xC97E_8168 => "logfs".into(),
+        0x0BD0_0BD0 => "lustre".into(),
+        0x5346_314D => "m1fs".into(),
+        0x137F => "minix".into(),
+        0x138F => "minix (30 char.)".into(),
+        0x2468 => "minix v2".into(),
+        0x2478 => "minix v2 (30 char.)".into(),
+        0x4D5A => "minix3".into(),
+        0x1980_0202 => "mqueue".into(),
+        0x4D44 => "msdos".into(),
+        0x564C => "novell".into(),
+        0x6969 => "nfs".into(),
+        0x6E66_7364 => "nfsd".into(),
+        0x3434 => "nilfs".into(),
+        0x6E73_6673 => "nsfs".into(),
+        0x5346_544E => "ntfs".into(),
+        0x9FA1 => "openprom".into(),
+        0x7461_636F => "ocfs2".into(),
+        0x794C_7630 => "overlayfs".into(),
+        0xAAD7_AAEA => "panfs".into(),
+        0x5049_5045 => "pipefs".into(),
+        0x7C7C_6673 => "prl_fs".into(),
+        0x9FA0 => "proc".into(),
+        0x6165_676C => "pstorefs".into(),
+        0x002F => "qnx4".into(),
+        0x6819_1122 => "qnx6".into(),
+        0x8584_58F6 => "ramfs".into(),
+        0x5265_4973 => "reiserfs".into(),
+        0x7275 => "romfs".into(),
+        0x6759_6969 => "rpc_pipefs".into(),
+        0x7363_6673 => "securityfs".into(),
+        0xF97C_FF8C => "selinux".into(),
+        0x4341_5D53 => "smackfs".into(),
+        0x517B => "smb".into(),
+        0xFE53_4D42 => "smb2".into(),
+        0xBEEF_DEAD => "snfs".into(),
+        0x534F_434B => "sockfs".into(),
+        0x7371_7368 => "squashfs".into(),
+        0x6265_6572 => "sysfs".into(),
+        0x012F_F7B6 => "sysv2".into(),
+        0x012F_F7B5 => "sysv4".into(),
+        0x0102_1994 => "tmpfs".into(),
+        0x7472_6163 => "tracefs".into(),
+        0x2405_1905 => "ubifs".into(),
+        0x1501_3346 => "udf".into(),
+        0x0001_1954 => "ufs".into(),
+        0x5419_0100 => "ufs".into(),
+        0x9FA2 => "usbdevfs".into(),
+        0x0102_1997 => "v9fs".into(),
+        0xBACB_ACBC => "vmhgfs".into(),
+        0xA501_FCF5 => "vxfs".into(),
+        0x565A_4653 => "vzfs".into(),
+        0x5346_4846 => "wslfs".into(),
+        0xABBA_1974 => "xenfs".into(),
+        0x012F_F7B4 => "xenix".into(),
+        0x5846_5342 => "xfs".into(),
+        0x012F_D16D => "xia".into(),
+        0x2FC1_2FC1 => "zfs".into(),
+        other => format!("UNKNOWN ({:#x})", other).into(),
+    }
+    // spell-checker:enable
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    #[cfg(unix)]
+    fn test_file_type() {
+        assert_eq!("block special file", pretty_filetype(S_IFBLK, 0));
+        assert_eq!("character special file", pretty_filetype(S_IFCHR, 0));
+        assert_eq!("regular file", pretty_filetype(S_IFREG, 1));
+        assert_eq!("regular empty file", pretty_filetype(S_IFREG, 0));
+        assert_eq!("weird file", pretty_filetype(0, 0));
+    }
+
+    #[test]
+    fn test_fs_type() {
+        // spell-checker:disable
+        assert_eq!("ext2/ext3", pretty_fstype(0xEF53));
+        assert_eq!("tmpfs", pretty_fstype(0x01021994));
+        assert_eq!("nfs", pretty_fstype(0x6969));
+        assert_eq!("btrfs", pretty_fstype(0x9123683e));
+        assert_eq!("xfs", pretty_fstype(0x58465342));
+        assert_eq!("zfs", pretty_fstype(0x2FC12FC1));
+        assert_eq!("ntfs", pretty_fstype(0x5346544e));
+        assert_eq!("fat", pretty_fstype(0x4006));
+        assert_eq!("UNKNOWN (0x1234)", pretty_fstype(0x1234));
+        // spell-checker:enable
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/mode.rs.html b/src/uucore/features/mode.rs.html new file mode 100644 index 000000000..34fe6dd86 --- /dev/null +++ b/src/uucore/features/mode.rs.html @@ -0,0 +1,325 @@ +mode.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Alex Lyon <arcterus@mail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (vars) fperm srwx
+
+use libc::{mode_t, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};
+
+pub fn parse_numeric(fperm: u32, mut mode: &str) -> Result<u32, String> {
+    let (op, pos) = parse_op(mode, Some('='))?;
+    mode = mode[pos..].trim().trim_start_matches('0');
+    if mode.len() > 4 {
+        Err(format!("mode is too large ({} > 7777)", mode))
+    } else {
+        match u32::from_str_radix(mode, 8) {
+            Ok(change) => Ok(match op {
+                '+' => fperm | change,
+                '-' => fperm & !change,
+                '=' => change,
+                _ => unreachable!(),
+            }),
+            Err(err) => Err(err.to_string()),
+        }
+    }
+}
+
+pub fn parse_symbolic(
+    mut fperm: u32,
+    mut mode: &str,
+    considering_dir: bool,
+) -> Result<u32, String> {
+    #[cfg(unix)]
+    use libc::umask;
+
+    let (mask, pos) = parse_levels(mode);
+    if pos == mode.len() {
+        return Err(format!("invalid mode ({})", mode));
+    }
+    let respect_umask = pos == 0;
+    let last_umask = unsafe { umask(0) };
+    mode = &mode[pos..];
+    while !mode.is_empty() {
+        let (op, pos) = parse_op(mode, None)?;
+        mode = &mode[pos..];
+        let (mut srwx, pos) = parse_change(mode, fperm, considering_dir);
+        if respect_umask {
+            srwx &= !(last_umask as u32);
+        }
+        mode = &mode[pos..];
+        match op {
+            '+' => fperm |= srwx & mask,
+            '-' => fperm &= !(srwx & mask),
+            '=' => fperm = (fperm & !mask) | (srwx & mask),
+            _ => unreachable!(),
+        }
+    }
+    unsafe {
+        umask(last_umask);
+    }
+    Ok(fperm)
+}
+
+fn parse_levels(mode: &str) -> (u32, usize) {
+    let mut mask = 0;
+    let mut pos = 0;
+    for ch in mode.chars() {
+        mask |= match ch {
+            'u' => 0o7700,
+            'g' => 0o7070,
+            'o' => 0o7007,
+            'a' => 0o7777,
+            _ => break,
+        };
+        pos += 1;
+    }
+    if pos == 0 {
+        mask = 0o7777; // default to 'a'
+    }
+    (mask, pos)
+}
+
+fn parse_op(mode: &str, default: Option<char>) -> Result<(char, usize), String> {
+    let ch = mode
+        .chars()
+        .next()
+        .ok_or_else(|| "unexpected end of mode".to_owned())?;
+    Ok(match ch {
+        '+' | '-' | '=' => (ch, 1),
+        _ => {
+            let ch = default.ok_or_else(|| {
+                format!("invalid operator (expected +, -, or =, but found {})", ch)
+            })?;
+            (ch, 0)
+        }
+    })
+}
+
+fn parse_change(mode: &str, fperm: u32, considering_dir: bool) -> (u32, usize) {
+    let mut srwx = fperm & 0o7000;
+    let mut pos = 0;
+    for ch in mode.chars() {
+        match ch {
+            'r' => srwx |= 0o444,
+            'w' => srwx |= 0o222,
+            'x' => srwx |= 0o111,
+            'X' => {
+                if considering_dir || (fperm & 0o0111) != 0 {
+                    srwx |= 0o111
+                }
+            }
+            's' => srwx |= 0o4000 | 0o2000,
+            't' => srwx |= 0o1000,
+            'u' => srwx = (fperm & 0o700) | ((fperm >> 3) & 0o070) | ((fperm >> 6) & 0o007),
+            'g' => srwx = ((fperm << 3) & 0o700) | (fperm & 0o070) | ((fperm >> 3) & 0o007),
+            'o' => srwx = ((fperm << 6) & 0o700) | ((fperm << 3) & 0o070) | (fperm & 0o007),
+            _ => break,
+        };
+        pos += 1;
+    }
+    if pos == 0 {
+        srwx = 0;
+    }
+    (srwx, pos)
+}
+
+pub fn parse_mode(mode: &str) -> Result<mode_t, String> {
+    let fperm = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+    let arr: &[char] = &['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
+    let result = if mode.contains(arr) {
+        parse_numeric(fperm as u32, mode)
+    } else {
+        parse_symbolic(fperm as u32, mode, true)
+    };
+    result.map(|mode| mode as mode_t)
+}
+
+#[cfg(test)]
+mod test {
+
+    #[test]
+    fn symbolic_modes() {
+        assert_eq!(super::parse_mode("u+x").unwrap(), 0o766);
+        assert_eq!(
+            super::parse_mode("+x").unwrap(),
+            if !crate::os::is_wsl_1() { 0o777 } else { 0o776 }
+        );
+        assert_eq!(super::parse_mode("a-w").unwrap(), 0o444);
+        assert_eq!(super::parse_mode("g-r").unwrap(), 0o626);
+    }
+
+    #[test]
+    fn numeric_modes() {
+        assert_eq!(super::parse_mode("644").unwrap(), 0o644);
+        assert_eq!(super::parse_mode("+100").unwrap(), 0o766);
+        assert_eq!(super::parse_mode("-4").unwrap(), 0o662);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/perms.rs.html b/src/uucore/features/perms.rs.html new file mode 100644 index 000000000..b3ff1912f --- /dev/null +++ b/src/uucore/features/perms.rs.html @@ -0,0 +1,695 @@ +perms.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+
+// This file is part of the uutils coreutils package.
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+use crate::error::UResult;
+pub use crate::features::entries;
+use crate::fs::resolve_relative_path;
+use crate::show_error;
+use libc::{self, gid_t, lchown, uid_t};
+use walkdir::WalkDir;
+
+use std::io::Error as IOError;
+use std::io::Result as IOResult;
+
+use std::ffi::CString;
+use std::fs::Metadata;
+use std::os::unix::fs::MetadataExt;
+
+use std::os::unix::ffi::OsStrExt;
+use std::path::Path;
+
+/// The various level of verbosity
+#[derive(PartialEq, Clone, Debug)]
+pub enum VerbosityLevel {
+    Silent,
+    Changes,
+    Verbose,
+    Normal,
+}
+#[derive(PartialEq, Clone, Debug)]
+pub struct Verbosity {
+    pub groups_only: bool,
+    pub level: VerbosityLevel,
+}
+
+/// Actually perform the change of owner on a path
+fn chown<P: AsRef<Path>>(path: P, uid: uid_t, gid: gid_t, follow: bool) -> IOResult<()> {
+    let path = path.as_ref();
+    let s = CString::new(path.as_os_str().as_bytes()).unwrap();
+    let ret = unsafe {
+        if follow {
+            libc::chown(s.as_ptr(), uid, gid)
+        } else {
+            lchown(s.as_ptr(), uid, gid)
+        }
+    };
+    if ret == 0 {
+        Ok(())
+    } else {
+        Err(IOError::last_os_error())
+    }
+}
+
+/// Perform the change of owner on a path
+/// with the various options
+/// and error messages management
+pub fn wrap_chown<P: AsRef<Path>>(
+    path: P,
+    meta: &Metadata,
+    dest_uid: Option<u32>,
+    dest_gid: Option<u32>,
+    follow: bool,
+    verbosity: Verbosity,
+) -> Result<String, String> {
+    let dest_uid = dest_uid.unwrap_or_else(|| meta.uid());
+    let dest_gid = dest_gid.unwrap_or_else(|| meta.gid());
+    let path = path.as_ref();
+    let mut out: String = String::new();
+
+    if let Err(e) = chown(path, dest_uid, dest_gid, follow) {
+        match verbosity.level {
+            VerbosityLevel::Silent => (),
+            level => {
+                out = format!(
+                    "changing {} of '{}': {}",
+                    if verbosity.groups_only {
+                        "group"
+                    } else {
+                        "ownership"
+                    },
+                    path.display(),
+                    e
+                );
+                if level == VerbosityLevel::Verbose {
+                    out = if verbosity.groups_only {
+                        format!(
+                            "{}\nfailed to change group of '{}' from {} to {}",
+                            out,
+                            path.display(),
+                            entries::gid2grp(meta.gid()).unwrap(),
+                            entries::gid2grp(dest_gid).unwrap()
+                        )
+                    } else {
+                        format!(
+                            "{}\nfailed to change ownership of '{}' from {}:{} to {}:{}",
+                            out,
+                            path.display(),
+                            entries::uid2usr(meta.uid()).unwrap(),
+                            entries::gid2grp(meta.gid()).unwrap(),
+                            entries::uid2usr(dest_uid).unwrap(),
+                            entries::gid2grp(dest_gid).unwrap()
+                        )
+                    };
+                };
+            }
+        }
+        return Err(out);
+    } else {
+        let changed = dest_uid != meta.uid() || dest_gid != meta.gid();
+        if changed {
+            match verbosity.level {
+                VerbosityLevel::Changes | VerbosityLevel::Verbose => {
+                    out = if verbosity.groups_only {
+                        format!(
+                            "changed group of '{}' from {} to {}",
+                            path.display(),
+                            entries::gid2grp(meta.gid()).unwrap(),
+                            entries::gid2grp(dest_gid).unwrap()
+                        )
+                    } else {
+                        format!(
+                            "changed ownership of '{}' from {}:{} to {}:{}",
+                            path.display(),
+                            entries::uid2usr(meta.uid()).unwrap(),
+                            entries::gid2grp(meta.gid()).unwrap(),
+                            entries::uid2usr(dest_uid).unwrap(),
+                            entries::gid2grp(dest_gid).unwrap()
+                        )
+                    };
+                }
+                _ => (),
+            };
+        } else if verbosity.level == VerbosityLevel::Verbose {
+            out = if verbosity.groups_only {
+                format!(
+                    "group of '{}' retained as {}",
+                    path.display(),
+                    entries::gid2grp(dest_gid).unwrap_or_default()
+                )
+            } else {
+                format!(
+                    "ownership of '{}' retained as {}:{}",
+                    path.display(),
+                    entries::uid2usr(dest_uid).unwrap(),
+                    entries::gid2grp(dest_gid).unwrap()
+                )
+            };
+        }
+    }
+    Ok(out)
+}
+
+pub enum IfFrom {
+    All,
+    User(u32),
+    Group(u32),
+    UserGroup(u32, u32),
+}
+
+pub struct ChownExecutor {
+    pub dest_uid: Option<u32>,
+    pub dest_gid: Option<u32>,
+    pub bit_flag: u8,
+    pub verbosity: Verbosity,
+    pub filter: IfFrom,
+    pub files: Vec<String>,
+    pub recursive: bool,
+    pub preserve_root: bool,
+    pub dereference: bool,
+}
+
+macro_rules! unwrap {
+    ($m:expr, $e:ident, $err:block) => {
+        match $m {
+            Ok(meta) => meta,
+            Err($e) => $err,
+        }
+    };
+}
+
+pub const FTS_COMFOLLOW: u8 = 1;
+pub const FTS_PHYSICAL: u8 = 1 << 1;
+pub const FTS_LOGICAL: u8 = 1 << 2;
+
+impl ChownExecutor {
+    pub fn exec(&self) -> UResult<()> {
+        let mut ret = 0;
+        for f in &self.files {
+            ret |= self.traverse(f);
+        }
+        if ret != 0 {
+            return Err(ret.into());
+        }
+        Ok(())
+    }
+
+    fn traverse<P: AsRef<Path>>(&self, root: P) -> i32 {
+        let follow_arg = self.dereference || self.bit_flag != FTS_PHYSICAL;
+        let path = root.as_ref();
+        let meta = match self.obtain_meta(path, follow_arg) {
+            Some(m) => m,
+            _ => return 1,
+        };
+
+        // Prohibit only if:
+        // (--preserve-root and -R present) &&
+        // (
+        //     (argument is not symlink && resolved to be '/') ||
+        //     (argument is symlink && should follow argument && resolved to be '/')
+        // )
+        if self.recursive && self.preserve_root {
+            let may_exist = if follow_arg {
+                path.canonicalize().ok()
+            } else {
+                let real = resolve_relative_path(path);
+                if real.is_dir() {
+                    Some(real.canonicalize().expect("failed to get real path"))
+                } else {
+                    Some(real.into_owned())
+                }
+            };
+
+            if let Some(p) = may_exist {
+                if p.parent().is_none() {
+                    show_error!("it is dangerous to operate recursively on '/'");
+                    show_error!("use --no-preserve-root to override this failsafe");
+                    return 1;
+                }
+            }
+        }
+
+        let ret = if self.matched(meta.uid(), meta.gid()) {
+            match wrap_chown(
+                path,
+                &meta,
+                self.dest_uid,
+                self.dest_gid,
+                follow_arg,
+                self.verbosity.clone(),
+            ) {
+                Ok(n) => {
+                    if !n.is_empty() {
+                        show_error!("{}", n);
+                    }
+                    0
+                }
+                Err(e) => {
+                    if self.verbosity.level != VerbosityLevel::Silent {
+                        show_error!("{}", e);
+                    }
+                    1
+                }
+            }
+        } else {
+            0
+        };
+
+        if !self.recursive {
+            ret
+        } else {
+            ret | self.dive_into(&root)
+        }
+    }
+
+    fn dive_into<P: AsRef<Path>>(&self, root: P) -> i32 {
+        let mut ret = 0;
+        let root = root.as_ref();
+        let follow = self.dereference || self.bit_flag & FTS_LOGICAL != 0;
+        for entry in WalkDir::new(root).follow_links(follow).min_depth(1) {
+            let entry = unwrap!(entry, e, {
+                ret = 1;
+                show_error!("{}", e);
+                continue;
+            });
+            let path = entry.path();
+            let meta = match self.obtain_meta(path, follow) {
+                Some(m) => m,
+                _ => {
+                    ret = 1;
+                    continue;
+                }
+            };
+
+            if !self.matched(meta.uid(), meta.gid()) {
+                continue;
+            }
+
+            ret = match wrap_chown(
+                path,
+                &meta,
+                self.dest_uid,
+                self.dest_gid,
+                follow,
+                self.verbosity.clone(),
+            ) {
+                Ok(n) => {
+                    if !n.is_empty() {
+                        show_error!("{}", n);
+                    }
+                    0
+                }
+                Err(e) => {
+                    if self.verbosity.level != VerbosityLevel::Silent {
+                        show_error!("{}", e);
+                    }
+                    1
+                }
+            }
+        }
+        ret
+    }
+
+    fn obtain_meta<P: AsRef<Path>>(&self, path: P, follow: bool) -> Option<Metadata> {
+        let path = path.as_ref();
+        let meta = if follow {
+            unwrap!(path.metadata(), e, {
+                match self.verbosity.level {
+                    VerbosityLevel::Silent => (),
+                    _ => show_error!("cannot access '{}': {}", path.display(), e),
+                }
+                return None;
+            })
+        } else {
+            unwrap!(path.symlink_metadata(), e, {
+                match self.verbosity.level {
+                    VerbosityLevel::Silent => (),
+                    _ => show_error!("cannot dereference '{}': {}", path.display(), e),
+                }
+                return None;
+            })
+        };
+        Some(meta)
+    }
+
+    #[inline]
+    fn matched(&self, uid: uid_t, gid: gid_t) -> bool {
+        match self.filter {
+            IfFrom::All => true,
+            IfFrom::User(u) => u == uid,
+            IfFrom::Group(g) => g == gid,
+            IfFrom::UserGroup(u, g) => u == uid && g == gid,
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/process.rs.html b/src/uucore/features/process.rs.html new file mode 100644 index 000000000..71c1243fa --- /dev/null +++ b/src/uucore/features/process.rs.html @@ -0,0 +1,285 @@ +process.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Maciej Dziardziel <fiedzia@gmail.com>
+// (c) Jian Zeng <anonymousknight96 AT gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (vars) cvar exitstatus
+// spell-checker:ignore (sys/unix) WIFSIGNALED
+
+use libc::{gid_t, pid_t, uid_t};
+use std::fmt;
+use std::io;
+use std::process::Child;
+use std::process::ExitStatus as StdExitStatus;
+use std::thread;
+use std::time::{Duration, Instant};
+
+/// `geteuid()` returns the effective user ID of the calling process.
+pub fn geteuid() -> uid_t {
+    unsafe { libc::geteuid() }
+}
+
+/// `getegid()` returns the effective group ID of the calling process.
+pub fn getegid() -> gid_t {
+    unsafe { libc::getegid() }
+}
+
+/// `getgid()` returns the real group ID of the calling process.
+pub fn getgid() -> gid_t {
+    unsafe { libc::getgid() }
+}
+
+/// `getuid()` returns the real user ID of the calling process.
+pub fn getuid() -> uid_t {
+    unsafe { libc::getuid() }
+}
+
+// This is basically sys::unix::process::ExitStatus
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub enum ExitStatus {
+    Code(i32),
+    Signal(i32),
+}
+
+#[allow(clippy::trivially_copy_pass_by_ref)]
+impl ExitStatus {
+    fn from_std_status(status: StdExitStatus) -> Self {
+        #[cfg(unix)]
+        {
+            use std::os::unix::process::ExitStatusExt;
+
+            if let Some(signal) = status.signal() {
+                return ExitStatus::Signal(signal);
+            }
+        }
+
+        // NOTE: this should never fail as we check if the program exited through a signal above
+        ExitStatus::Code(status.code().unwrap())
+    }
+
+    pub fn success(&self) -> bool {
+        match *self {
+            ExitStatus::Code(code) => code == 0,
+            _ => false,
+        }
+    }
+
+    pub fn code(&self) -> Option<i32> {
+        match *self {
+            ExitStatus::Code(code) => Some(code),
+            _ => None,
+        }
+    }
+
+    pub fn signal(&self) -> Option<i32> {
+        match *self {
+            ExitStatus::Signal(code) => Some(code),
+            _ => None,
+        }
+    }
+}
+
+impl fmt::Display for ExitStatus {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            ExitStatus::Code(code) => write!(f, "exit code: {}", code),
+            ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
+        }
+    }
+}
+
+/// Missing methods for Child objects
+pub trait ChildExt {
+    /// Send a signal to a Child process.
+    fn send_signal(&mut self, signal: usize) -> io::Result<()>;
+
+    /// Wait for a process to finish or return after the specified duration.
+    /// A `timeout` of zero disables the timeout.
+    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>>;
+}
+
+impl ChildExt for Child {
+    fn send_signal(&mut self, signal: usize) -> io::Result<()> {
+        if unsafe { libc::kill(self.id() as pid_t, signal as i32) } != 0 {
+            Err(io::Error::last_os_error())
+        } else {
+            Ok(())
+        }
+    }
+
+    fn wait_or_timeout(&mut self, timeout: Duration) -> io::Result<Option<ExitStatus>> {
+        if timeout == Duration::from_micros(0) {
+            return self
+                .wait()
+                .map(|status| Some(ExitStatus::from_std_status(status)));
+        }
+        // .try_wait() doesn't drop stdin, so we do it manually
+        drop(self.stdin.take());
+
+        let start = Instant::now();
+        loop {
+            if let Some(status) = self.try_wait()? {
+                return Ok(Some(ExitStatus::from_std_status(status)));
+            }
+
+            if start.elapsed() >= timeout {
+                break;
+            }
+
+            // XXX: this is kinda gross, but it's cleaner than starting a thread just to wait
+            //      (which was the previous solution).  We might want to use a different duration
+            //      here as well
+            thread::sleep(Duration::from_millis(100));
+        }
+
+        Ok(None)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/ringbuffer.rs.html b/src/uucore/features/ringbuffer.rs.html new file mode 100644 index 000000000..a34b16ee7 --- /dev/null +++ b/src/uucore/features/ringbuffer.rs.html @@ -0,0 +1,271 @@ +ringbuffer.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+
+//! A fixed-size ring buffer.
+use std::collections::VecDeque;
+
+/// A fixed-size ring buffer backed by a `VecDeque`.
+///
+/// If the ring buffer is not full, then calling the [`push_back`]
+/// method appends elements, as in a [`VecDeque`]. If the ring buffer
+/// is full, then calling [`push_back`] removes the element at the
+/// front of the buffer (in a first-in, first-out manner) before
+/// appending the new element to the back of the buffer.
+///
+/// Use [`from_iter`] to take the last `size` elements from an
+/// iterator.
+///
+/// # Examples
+///
+/// After exceeding the size limit, the oldest elements are dropped in
+/// favor of the newest element:
+///
+/// ```rust,ignore
+/// let mut buffer: RingBuffer<u8> = RingBuffer::new(2);
+/// buffer.push_back(0);
+/// buffer.push_back(1);
+/// buffer.push_back(2);
+/// assert_eq!(vec![1, 2], buffer.data);
+/// ```
+///
+/// Take the last `n` elements from an iterator:
+///
+/// ```rust,ignore
+/// let iter = [0, 1, 2].iter();
+/// let actual = RingBuffer::from_iter(iter, 2).data;
+/// let expected = VecDeque::from_iter([1, 2].iter());
+/// assert_eq!(expected, actual);
+/// ```
+pub struct RingBuffer<T> {
+    pub data: VecDeque<T>,
+    size: usize,
+}
+
+impl<T> RingBuffer<T> {
+    pub fn new(size: usize) -> RingBuffer<T> {
+        RingBuffer {
+            data: VecDeque::new(),
+            size,
+        }
+    }
+
+    pub fn from_iter(iter: impl Iterator<Item = T>, size: usize) -> RingBuffer<T> {
+        let mut ring_buffer = RingBuffer::new(size);
+        for value in iter {
+            ring_buffer.push_back(value);
+        }
+        ring_buffer
+    }
+
+    /// Append a value to the end of the ring buffer.
+    ///
+    /// If the ring buffer is not full, this method return [`None`]. If
+    /// the ring buffer is full, appending a new element will cause the
+    /// oldest element to be evicted. In that case this method returns
+    /// that element, or `None`.
+    ///
+    /// In the special case where the size limit is zero, each call to
+    /// this method with input `value` returns `Some(value)`, because
+    /// the input is immediately evicted.
+    ///
+    /// # Examples
+    ///
+    /// Appending an element when the buffer is full returns the oldest
+    /// element:
+    ///
+    /// ```rust,ignore
+    /// let mut buf = RingBuffer::new(3);
+    /// assert_eq!(None, buf.push_back(0));
+    /// assert_eq!(None, buf.push_back(1));
+    /// assert_eq!(None, buf.push_back(2));
+    /// assert_eq!(Some(0), buf.push_back(3));
+    /// ```
+    ///
+    /// If the size limit is zero, then this method always returns the
+    /// input value:
+    ///
+    /// ```rust,ignore
+    /// let mut buf = RingBuffer::new(0);
+    /// assert_eq!(Some(0), buf.push_back(0));
+    /// assert_eq!(Some(1), buf.push_back(1));
+    /// assert_eq!(Some(2), buf.push_back(2));
+    /// ```
+    pub fn push_back(&mut self, value: T) -> Option<T> {
+        if self.size == 0 {
+            return Some(value);
+        }
+        let result = if self.size <= self.data.len() {
+            self.data.pop_front()
+        } else {
+            None
+        };
+        self.data.push_back(value);
+        result
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use crate::ringbuffer::RingBuffer;
+    use std::collections::VecDeque;
+
+    #[test]
+    fn test_size_limit_zero() {
+        let mut buf = RingBuffer::new(0);
+        assert_eq!(Some(0), buf.push_back(0));
+        assert_eq!(Some(1), buf.push_back(1));
+        assert_eq!(Some(2), buf.push_back(2));
+    }
+
+    #[test]
+    fn test_evict_oldest() {
+        let mut buf = RingBuffer::new(2);
+        assert_eq!(None, buf.push_back(0));
+        assert_eq!(None, buf.push_back(1));
+        assert_eq!(Some(0), buf.push_back(2));
+    }
+
+    #[test]
+    fn test_from_iter() {
+        let iter = [0, 1, 2].iter();
+        let actual = RingBuffer::from_iter(iter, 2).data;
+        let expected: VecDeque<&i32> = [1, 2].iter().collect();
+        assert_eq!(expected, actual);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/signals.rs.html b/src/uucore/features/signals.rs.html new file mode 100644 index 000000000..fb7312fd6 --- /dev/null +++ b/src/uucore/features/signals.rs.html @@ -0,0 +1,269 @@ +signals.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Maciej Dziardziel <fiedzia@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE file
+// that was distributed with this source code.
+
+// spell-checker:ignore (vars/api) fcntl setrlimit setitimer
+// spell-checker:ignore (vars/signals) ABRT ALRM CHLD SEGV SIGABRT SIGALRM SIGBUS SIGCHLD SIGCONT SIGEMT SIGFPE SIGHUP SIGILL SIGINFO SIGINT SIGIO SIGIOT SIGKILL SIGPIPE SIGPROF SIGQUIT SIGSEGV SIGSTOP SIGSYS SIGTERM SIGTRAP SIGTSTP SIGTTIN SIGTTOU SIGURG SIGUSR SIGVTALRM SIGWINCH SIGXCPU SIGXFSZ STKFLT TSTP TTIN TTOU VTALRM XCPU XFSZ
+
+pub static DEFAULT_SIGNAL: usize = 15;
+
+/*
+
+Linux Programmer's Manual
+
+ 1 HUP      2 INT      3 QUIT     4 ILL      5 TRAP     6 ABRT     7 BUS
+ 8 FPE      9 KILL    10 USR1    11 SEGV    12 USR2    13 PIPE    14 ALRM
+15 TERM    16 STKFLT  17 CHLD    18 CONT    19 STOP    20 TSTP    21 TTIN
+22 TTOU    23 URG     24 XCPU    25 XFSZ    26 VTALRM  27 PROF    28 WINCH
+29 POLL    30 PWR     31 SYS
+
+
+*/
+
+#[cfg(target_os = "linux")]
+pub static ALL_SIGNALS: [&str; 32] = [
+    "EXIT", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "BUS", "FPE", "KILL", "USR1", "SEGV",
+    "USR2", "PIPE", "ALRM", "TERM", "STKFLT", "CHLD", "CONT", "STOP", "TSTP", "TTIN", "TTOU",
+    "URG", "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "POLL", "PWR", "SYS",
+];
+
+/*
+
+
+https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html
+
+
+No    Name         Default Action       Description
+1     SIGHUP       terminate process    terminal line hangup
+2     SIGINT       terminate process    interrupt program
+3     SIGQUIT      create core image    quit program
+4     SIGILL       create core image    illegal instruction
+5     SIGTRAP      create core image    trace trap
+6     SIGABRT      create core image    abort program (formerly SIGIOT)
+7     SIGEMT       create core image    emulate instruction executed
+8     SIGFPE       create core image    floating-point exception
+9     SIGKILL      terminate process    kill program
+10    SIGBUS       create core image    bus error
+11    SIGSEGV      create core image    segmentation violation
+12    SIGSYS       create core image    non-existent system call invoked
+13    SIGPIPE      terminate process    write on a pipe with no reader
+14    SIGALRM      terminate process    real-time timer expired
+15    SIGTERM      terminate process    software termination signal
+16    SIGURG       discard signal       urgent condition present on socket
+17    SIGSTOP      stop process         stop (cannot be caught or ignored)
+18    SIGTSTP      stop process         stop signal generated from keyboard
+19    SIGCONT      discard signal       continue after stop
+20    SIGCHLD      discard signal       child status has changed
+21    SIGTTIN      stop process         background read attempted from control terminal
+22    SIGTTOU      stop process         background write attempted to control terminal
+23    SIGIO        discard signal       I/O is possible on a descriptor (see fcntl(2))
+24    SIGXCPU      terminate process    cpu time limit exceeded (see setrlimit(2))
+25    SIGXFSZ      terminate process    file size limit exceeded (see setrlimit(2))
+26    SIGVTALRM    terminate process    virtual time alarm (see setitimer(2))
+27    SIGPROF      terminate process    profiling timer alarm (see setitimer(2))
+28    SIGWINCH     discard signal       Window size change
+29    SIGINFO      discard signal       status request from keyboard
+30    SIGUSR1      terminate process    User defined signal 1
+31    SIGUSR2      terminate process    User defined signal 2
+
+*/
+
+#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
+pub static ALL_SIGNALS: [&str; 32] = [
+    "EXIT", "HUP", "INT", "QUIT", "ILL", "TRAP", "ABRT", "EMT", "FPE", "KILL", "BUS", "SEGV",
+    "SYS", "PIPE", "ALRM", "TERM", "URG", "STOP", "TSTP", "CONT", "CHLD", "TTIN", "TTOU", "IO",
+    "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1", "USR2",
+];
+
+pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
+    if let Ok(value) = signal_name_or_value.parse() {
+        if is_signal(value) {
+            return Some(value);
+        } else {
+            return None;
+        }
+    }
+    let signal_name = signal_name_or_value.trim_start_matches("SIG");
+
+    ALL_SIGNALS.iter().position(|&s| s == signal_name)
+}
+
+pub fn is_signal(num: usize) -> bool {
+    num < ALL_SIGNALS.len()
+}
+
+pub fn signal_name_by_value(signal_value: usize) -> Option<&'static str> {
+    ALL_SIGNALS.get(signal_value).copied()
+}
+
+#[test]
+fn signal_by_value() {
+    assert_eq!(signal_by_name_or_value("0"), Some(0));
+    for (value, _signal) in ALL_SIGNALS.iter().enumerate() {
+        assert_eq!(signal_by_name_or_value(&value.to_string()), Some(value));
+    }
+}
+
+#[test]
+fn signal_by_short_name() {
+    for (value, signal) in ALL_SIGNALS.iter().enumerate() {
+        assert_eq!(signal_by_name_or_value(signal), Some(value));
+    }
+}
+
+#[test]
+fn signal_by_long_name() {
+    for (value, signal) in ALL_SIGNALS.iter().enumerate() {
+        assert_eq!(
+            signal_by_name_or_value(&format!("SIG{}", signal)),
+            Some(value)
+        );
+    }
+}
+
+#[test]
+fn name() {
+    for (value, signal) in ALL_SIGNALS.iter().enumerate() {
+        assert_eq!(signal_name_by_value(value), Some(*signal));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/utmpx.rs.html b/src/uucore/features/utmpx.rs.html new file mode 100644 index 000000000..78d9cf5bc --- /dev/null +++ b/src/uucore/features/utmpx.rs.html @@ -0,0 +1,591 @@ +utmpx.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Jian Zeng <anonymousknight96@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+//
+//! Aims to provide platform-independent methods to obtain login records
+//!
+//! **ONLY** support linux, macos and freebsd for the time being
+//!
+//! # Examples:
+//!
+//! ```
+//! use uucore::utmpx::Utmpx;
+//! for ut in Utmpx::iter_all_records() {
+//!     if ut.is_user_process() {
+//!         println!("{}: {}", ut.host(), ut.user())
+//!     }
+//! }
+//! ```
+//!
+//! Specifying the path to login record:
+//!
+//! ```
+//! use uucore::utmpx::Utmpx;
+//! for ut in Utmpx::iter_all_records().read_from("/some/where/else") {
+//!     if ut.is_user_process() {
+//!         println!("{}: {}", ut.host(), ut.user())
+//!     }
+//! }
+//! ```
+
+pub extern crate time;
+use self::time::{Timespec, Tm};
+
+use std::ffi::CString;
+use std::io::Error as IOError;
+use std::io::Result as IOResult;
+use std::ptr;
+
+pub use self::ut::*;
+use libc::utmpx;
+// pub use libc::getutxid;
+// pub use libc::getutxline;
+// pub use libc::pututxline;
+pub use libc::endutxent;
+pub use libc::getutxent;
+pub use libc::setutxent;
+#[cfg(any(target_vendor = "apple", target_os = "linux", target_os = "netbsd"))]
+pub use libc::utmpxname;
+#[cfg(target_os = "freebsd")]
+pub unsafe extern "C" fn utmpxname(_file: *const libc::c_char) -> libc::c_int {
+    0
+}
+
+pub use crate::*; // import macros from `../../macros.rs`
+
+// In case the c_char array doesn't end with NULL
+macro_rules! chars2string {
+    ($arr:expr) => {
+        $arr.iter()
+            .take_while(|i| **i > 0)
+            .map(|&i| i as u8 as char)
+            .collect::<String>()
+    };
+}
+
+#[cfg(target_os = "linux")]
+mod ut {
+    pub static DEFAULT_FILE: &str = "/var/run/utmp";
+
+    pub use libc::__UT_HOSTSIZE as UT_HOSTSIZE;
+    pub use libc::__UT_LINESIZE as UT_LINESIZE;
+    pub use libc::__UT_NAMESIZE as UT_NAMESIZE;
+    pub const UT_IDSIZE: usize = 4;
+
+    pub use libc::ACCOUNTING;
+    pub use libc::BOOT_TIME;
+    pub use libc::DEAD_PROCESS;
+    pub use libc::EMPTY;
+    pub use libc::INIT_PROCESS;
+    pub use libc::LOGIN_PROCESS;
+    pub use libc::NEW_TIME;
+    pub use libc::OLD_TIME;
+    pub use libc::RUN_LVL;
+    pub use libc::USER_PROCESS;
+}
+
+#[cfg(target_vendor = "apple")]
+mod ut {
+    pub static DEFAULT_FILE: &str = "/var/run/utmpx";
+
+    pub use libc::_UTX_HOSTSIZE as UT_HOSTSIZE;
+    pub use libc::_UTX_IDSIZE as UT_IDSIZE;
+    pub use libc::_UTX_LINESIZE as UT_LINESIZE;
+    pub use libc::_UTX_USERSIZE as UT_NAMESIZE;
+
+    pub use libc::ACCOUNTING;
+    pub use libc::BOOT_TIME;
+    pub use libc::DEAD_PROCESS;
+    pub use libc::EMPTY;
+    pub use libc::INIT_PROCESS;
+    pub use libc::LOGIN_PROCESS;
+    pub use libc::NEW_TIME;
+    pub use libc::OLD_TIME;
+    pub use libc::RUN_LVL;
+    pub use libc::SHUTDOWN_TIME;
+    pub use libc::SIGNATURE;
+    pub use libc::USER_PROCESS;
+}
+
+#[cfg(target_os = "freebsd")]
+mod ut {
+    pub static DEFAULT_FILE: &str = "";
+
+    pub const UT_LINESIZE: usize = 16;
+    pub const UT_NAMESIZE: usize = 32;
+    pub const UT_IDSIZE: usize = 8;
+    pub const UT_HOSTSIZE: usize = 128;
+
+    pub use libc::BOOT_TIME;
+    pub use libc::DEAD_PROCESS;
+    pub use libc::EMPTY;
+    pub use libc::INIT_PROCESS;
+    pub use libc::LOGIN_PROCESS;
+    pub use libc::NEW_TIME;
+    pub use libc::OLD_TIME;
+    pub use libc::SHUTDOWN_TIME;
+    pub use libc::USER_PROCESS;
+}
+
+#[cfg(target_os = "netbsd")]
+mod ut {
+    pub static DEFAULT_FILE: &str = "/var/run/utmpx";
+
+    pub const ACCOUNTING: usize = 9;
+    pub const SHUTDOWN_TIME: usize = 11;
+
+    pub use libc::_UTX_HOSTSIZE as UT_HOSTSIZE;
+    pub use libc::_UTX_IDSIZE as UT_IDSIZE;
+    pub use libc::_UTX_LINESIZE as UT_LINESIZE;
+    pub use libc::_UTX_USERSIZE as UT_NAMESIZE;
+
+    pub use libc::ACCOUNTING;
+    pub use libc::DEAD_PROCESS;
+    pub use libc::EMPTY;
+    pub use libc::INIT_PROCESS;
+    pub use libc::LOGIN_PROCESS;
+    pub use libc::NEW_TIME;
+    pub use libc::OLD_TIME;
+    pub use libc::RUN_LVL;
+    pub use libc::SIGNATURE;
+    pub use libc::USER_PROCESS;
+}
+
+pub struct Utmpx {
+    inner: utmpx,
+}
+
+impl Utmpx {
+    /// A.K.A. ut.ut_type
+    pub fn record_type(&self) -> i16 {
+        self.inner.ut_type as i16
+    }
+    /// A.K.A. ut.ut_pid
+    pub fn pid(&self) -> i32 {
+        self.inner.ut_pid as i32
+    }
+    /// A.K.A. ut.ut_id
+    pub fn terminal_suffix(&self) -> String {
+        chars2string!(self.inner.ut_id)
+    }
+    /// A.K.A. ut.ut_user
+    pub fn user(&self) -> String {
+        chars2string!(self.inner.ut_user)
+    }
+    /// A.K.A. ut.ut_host
+    pub fn host(&self) -> String {
+        chars2string!(self.inner.ut_host)
+    }
+    /// A.K.A. ut.ut_line
+    pub fn tty_device(&self) -> String {
+        chars2string!(self.inner.ut_line)
+    }
+    /// A.K.A. ut.ut_tv
+    pub fn login_time(&self) -> Tm {
+        time::at(Timespec::new(
+            self.inner.ut_tv.tv_sec as i64,
+            self.inner.ut_tv.tv_usec as i32,
+        ))
+    }
+    /// A.K.A. ut.ut_exit
+    ///
+    /// Return (e_termination, e_exit)
+    #[cfg(any(target_os = "linux", target_os = "android"))]
+    pub fn exit_status(&self) -> (i16, i16) {
+        (self.inner.ut_exit.e_termination, self.inner.ut_exit.e_exit)
+    }
+    /// A.K.A. ut.ut_exit
+    ///
+    /// Return (0, 0) on Non-Linux platform
+    #[cfg(not(any(target_os = "linux", target_os = "android")))]
+    pub fn exit_status(&self) -> (i16, i16) {
+        (0, 0)
+    }
+    /// Consumes the `Utmpx`, returning the underlying C struct utmpx
+    pub fn into_inner(self) -> utmpx {
+        self.inner
+    }
+    pub fn is_user_process(&self) -> bool {
+        !self.user().is_empty() && self.record_type() == USER_PROCESS
+    }
+
+    /// Canonicalize host name using DNS
+    pub fn canon_host(&self) -> IOResult<String> {
+        let host = self.host();
+
+        // TODO: change to use `split_once` when MSRV hits 1.52.0
+        // let (hostname, display) = host.split_once(':').unwrap_or((&host, ""));
+        let mut h = host.split(':');
+        let hostname = h.next().unwrap_or(&host);
+        let display = h.next().unwrap_or("");
+
+        if !hostname.is_empty() {
+            extern crate dns_lookup;
+            use dns_lookup::{getaddrinfo, AddrInfoHints};
+
+            const AI_CANONNAME: i32 = 0x2;
+            let hints = AddrInfoHints {
+                flags: AI_CANONNAME,
+                ..AddrInfoHints::default()
+            };
+            let sockets = getaddrinfo(Some(hostname), None, Some(hints))
+                .unwrap()
+                .collect::<IOResult<Vec<_>>>()?;
+            for socket in sockets {
+                if let Some(ai_canonname) = socket.canonname {
+                    return Ok(if display.is_empty() {
+                        ai_canonname
+                    } else {
+                        format!("{}:{}", ai_canonname, display)
+                    });
+                }
+            }
+        }
+
+        Ok(host.to_string())
+    }
+
+    pub fn iter_all_records() -> UtmpxIter {
+        UtmpxIter
+    }
+}
+
+/// Iterator of login records
+pub struct UtmpxIter;
+
+impl UtmpxIter {
+    /// Sets the name of the utmpx-format file for the other utmpx functions to access.
+    ///
+    /// If not set, default record file will be used(file path depends on the target OS)
+    pub fn read_from(self, f: &str) -> Self {
+        let res = unsafe {
+            let cstring = CString::new(f).unwrap();
+            utmpxname(cstring.as_ptr())
+        };
+        if res != 0 {
+            show_warning!("utmpxname: {}", IOError::last_os_error());
+        }
+        unsafe {
+            setutxent();
+        }
+        self
+    }
+}
+
+impl Iterator for UtmpxIter {
+    type Item = Utmpx;
+    fn next(&mut self) -> Option<Self::Item> {
+        unsafe {
+            let res = getutxent();
+            if !res.is_null() {
+                Some(Utmpx {
+                    inner: ptr::read(res as *const _),
+                })
+            } else {
+                endutxent();
+                None
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/zero_copy.rs.html b/src/uucore/features/zero_copy.rs.html new file mode 100644 index 000000000..0b314eb97 --- /dev/null +++ b/src/uucore/features/zero_copy.rs.html @@ -0,0 +1,301 @@ +zero_copy.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+
+use self::platform::*;
+
+use std::io::{self, Write};
+
+mod platform;
+
+pub trait AsRawObject {
+    fn as_raw_object(&self) -> RawObject;
+}
+
+pub trait FromRawObject: Sized {
+    /// # Safety
+    /// ToDO ...
+    unsafe fn from_raw_object(obj: RawObject) -> Option<Self>;
+}
+
+// TODO: also make a SpliceWriter that takes an input fd and and output fd and uses splice() to
+//       transfer data
+// TODO: make a TeeWriter or something that takes an input fd and two output fds and uses tee() to
+//       transfer to both output fds
+
+enum InnerZeroCopyWriter<T: Write + Sized> {
+    Platform(PlatformZeroCopyWriter),
+    Standard(T),
+}
+
+impl<T: Write + Sized> Write for InnerZeroCopyWriter<T> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match self {
+            InnerZeroCopyWriter::Platform(ref mut writer) => writer.write(buf),
+            InnerZeroCopyWriter::Standard(ref mut writer) => writer.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        match self {
+            InnerZeroCopyWriter::Platform(ref mut writer) => writer.flush(),
+            InnerZeroCopyWriter::Standard(ref mut writer) => writer.flush(),
+        }
+    }
+}
+
+pub struct ZeroCopyWriter<T: Write + AsRawObject + Sized> {
+    /// This field is never used, but we need it to drop file descriptors
+    #[allow(dead_code)]
+    raw_obj_owner: Option<T>,
+
+    inner: InnerZeroCopyWriter<T>,
+}
+
+struct TransformContainer<'a, A: Write + AsRawObject + Sized, B: Write + Sized> {
+    /// This field is never used and probably could be converted into PhantomData, but might be
+    /// useful for restructuring later (at the moment it's basically left over from an earlier
+    /// design)
+    #[allow(dead_code)]
+    original: Option<&'a mut A>,
+
+    transformed: Option<B>,
+}
+
+impl<'a, A: Write + AsRawObject + Sized, B: Write + Sized> Write for TransformContainer<'a, A, B> {
+    fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
+        self.transformed.as_mut().unwrap().write(bytes)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.transformed.as_mut().unwrap().flush()
+    }
+}
+
+impl<'a, A: Write + AsRawObject + Sized, B: Write + Sized> AsRawObject
+    for TransformContainer<'a, A, B>
+{
+    fn as_raw_object(&self) -> RawObject {
+        panic!("Test should never be used")
+    }
+}
+
+impl<T: Write + AsRawObject + Sized> ZeroCopyWriter<T> {
+    pub fn new(writer: T) -> Self {
+        let raw_obj = writer.as_raw_object();
+        match unsafe { PlatformZeroCopyWriter::new(raw_obj) } {
+            Ok(inner) => ZeroCopyWriter {
+                raw_obj_owner: Some(writer),
+                inner: InnerZeroCopyWriter::Platform(inner),
+            },
+            _ => {
+                // creating the splice writer failed for whatever reason, so just make a default
+                // writer
+                ZeroCopyWriter {
+                    raw_obj_owner: None,
+                    inner: InnerZeroCopyWriter::Standard(writer),
+                }
+            }
+        }
+    }
+
+    pub fn with_default<'a: 'b, 'b, F, W>(
+        writer: &'a mut T,
+        func: F,
+    ) -> ZeroCopyWriter<impl Write + AsRawObject + Sized + 'b>
+    where
+        F: Fn(&'a mut T) -> W,
+        W: Write + Sized + 'b,
+    {
+        let raw_obj = writer.as_raw_object();
+        match unsafe { PlatformZeroCopyWriter::new(raw_obj) } {
+            Ok(inner) => ZeroCopyWriter {
+                raw_obj_owner: Some(TransformContainer {
+                    original: Some(writer),
+                    transformed: None,
+                }),
+                inner: InnerZeroCopyWriter::Platform(inner),
+            },
+            _ => {
+                // XXX: should func actually consume writer and leave it up to the user to save the value?
+                //      maybe provide a default stdin method then?  in some cases it would make more sense for the
+                //      value to be consumed
+                let real_writer = func(writer);
+                ZeroCopyWriter {
+                    raw_obj_owner: None,
+                    inner: InnerZeroCopyWriter::Standard(TransformContainer {
+                        original: None,
+                        transformed: Some(real_writer),
+                    }),
+                }
+            }
+        }
+    }
+
+    // XXX: unsure how to get something like this working without allocating, so not providing it
+    /*pub fn stdout() -> ZeroCopyWriter<impl Write + AsRawObject + Sized> {
+       let mut stdout = io::stdout();
+       ZeroCopyWriter::with_default(&mut stdout, |stdout| {
+          stdout.lock()
+       })
+    }*/
+}
+
+impl<T: Write + AsRawObject + Sized> Write for ZeroCopyWriter<T> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.inner.write(buf)
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.flush()
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/zero_copy/platform.rs.html b/src/uucore/features/zero_copy/platform.rs.html new file mode 100644 index 000000000..27d74d4c3 --- /dev/null +++ b/src/uucore/features/zero_copy/platform.rs.html @@ -0,0 +1,47 @@ +platform.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+pub use self::linux::*;
+#[cfg(unix)]
+pub use self::unix::*;
+#[cfg(windows)]
+pub use self::windows::*;
+
+// Add any operating systems we support here
+#[cfg(not(any(target_os = "linux", target_os = "android")))]
+pub use self::default::*;
+
+#[cfg(any(target_os = "linux", target_os = "android"))]
+mod linux;
+#[cfg(unix)]
+mod unix;
+#[cfg(windows)]
+mod windows;
+
+// Add any operating systems we support here
+#[cfg(not(any(target_os = "linux", target_os = "android")))]
+mod default;
+
+
\ No newline at end of file diff --git a/src/uucore/features/zero_copy/platform/linux.rs.html b/src/uucore/features/zero_copy/platform/linux.rs.html new file mode 100644 index 000000000..9f9b5aa4b --- /dev/null +++ b/src/uucore/features/zero_copy/platform/linux.rs.html @@ -0,0 +1,231 @@ +linux.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+
+use std::io::{self, Write};
+use std::os::unix::io::RawFd;
+
+use libc::{O_APPEND, S_IFIFO, S_IFREG};
+use nix::errno::Errno;
+use nix::fcntl::{fcntl, splice, vmsplice, FcntlArg, SpliceFFlags};
+use nix::sys::stat::{fstat, FileStat};
+use nix::sys::uio::IoVec;
+use nix::unistd::pipe;
+use platform_info::{PlatformInfo, Uname};
+
+use crate::features::zero_copy::{FromRawObject, RawObject};
+
+lazy_static::lazy_static! {
+    static ref IN_WSL: bool = {
+        let info = PlatformInfo::new().unwrap();
+        info.release().contains("Microsoft")
+    };
+}
+
+pub struct PlatformZeroCopyWriter {
+    raw_obj: RawObject,
+    read_pipe: RawFd,
+    write_pipe: RawFd,
+    #[allow(clippy::type_complexity)]
+    write_fn: fn(&mut PlatformZeroCopyWriter, &[IoVec<&[u8]>], usize) -> io::Result<usize>,
+}
+
+impl PlatformZeroCopyWriter {
+    pub unsafe fn new(raw_obj: RawObject) -> nix::Result<Self> {
+        if *IN_WSL {
+            // apparently WSL hasn't implemented vmsplice(), causing writes to fail
+            // thus, we will just say zero-copy doesn't work there rather than working
+            // around it
+            return Err(nix::Error::from(Errno::EOPNOTSUPP));
+        }
+
+        let stat_info: FileStat = fstat(raw_obj)?;
+        let access_mode: libc::c_int = fcntl(raw_obj, FcntlArg::F_GETFL)?;
+
+        let is_regular = (stat_info.st_mode & S_IFREG) != 0;
+        let is_append = (access_mode & O_APPEND) != 0;
+        let is_fifo = (stat_info.st_mode & S_IFIFO) != 0;
+
+        if is_regular && !is_append {
+            let (read_pipe, write_pipe) = pipe()?;
+
+            Ok(PlatformZeroCopyWriter {
+                raw_obj,
+                read_pipe,
+                write_pipe,
+                write_fn: write_regular,
+            })
+        } else if is_fifo {
+            Ok(PlatformZeroCopyWriter {
+                raw_obj,
+                read_pipe: Default::default(),
+                write_pipe: Default::default(),
+                write_fn: write_fifo,
+            })
+        } else {
+            // FIXME: how to error?
+            Err(nix::Error::from(Errno::UnknownErrno))
+        }
+    }
+}
+
+impl FromRawObject for PlatformZeroCopyWriter {
+    unsafe fn from_raw_object(obj: RawObject) -> Option<Self> {
+        PlatformZeroCopyWriter::new(obj).ok()
+    }
+}
+
+impl Write for PlatformZeroCopyWriter {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        let iovec = &[IoVec::from_slice(buf)];
+
+        let func = self.write_fn;
+        func(self, iovec, buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        // XXX: not sure if we need anything else
+        Ok(())
+    }
+}
+
+fn write_regular(
+    writer: &mut PlatformZeroCopyWriter,
+    iovec: &[IoVec<&[u8]>],
+    len: usize,
+) -> io::Result<usize> {
+    vmsplice(writer.write_pipe, iovec, SpliceFFlags::empty())
+        .and_then(|_| {
+            splice(
+                writer.read_pipe,
+                None,
+                writer.raw_obj,
+                None,
+                len,
+                SpliceFFlags::empty(),
+            )
+        })
+        .map_err(|_| io::Error::last_os_error())
+}
+
+fn write_fifo(
+    writer: &mut PlatformZeroCopyWriter,
+    iovec: &[IoVec<&[u8]>],
+    _len: usize,
+) -> io::Result<usize> {
+    vmsplice(writer.raw_obj, iovec, SpliceFFlags::empty()).map_err(|_| io::Error::last_os_error())
+}
+
+
\ No newline at end of file diff --git a/src/uucore/features/zero_copy/platform/unix.rs.html b/src/uucore/features/zero_copy/platform/unix.rs.html new file mode 100644 index 000000000..e8e978bbc --- /dev/null +++ b/src/uucore/features/zero_copy/platform/unix.rs.html @@ -0,0 +1,41 @@ +unix.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+
+use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+
+use crate::features::zero_copy::{AsRawObject, FromRawObject};
+
+pub type RawObject = RawFd;
+
+impl<T: AsRawFd> AsRawObject for T {
+    fn as_raw_object(&self) -> RawObject {
+        self.as_raw_fd()
+    }
+}
+
+// FIXME: check if this works right
+impl<T: FromRawFd> FromRawObject for T {
+    unsafe fn from_raw_object(obj: RawObject) -> Option<Self> {
+        Some(T::from_raw_fd(obj))
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/lib.rs.html b/src/uucore/lib.rs.html new file mode 100644 index 000000000..a0cfe3658 --- /dev/null +++ b/src/uucore/lib.rs.html @@ -0,0 +1,615 @@ +lib.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+
+// library ~ (core/bundler file)
+
+// Copyright (C) ~ Alex Lyon <arcterus@mail.com>
+// Copyright (C) ~ Roy Ivy III <rivy.dev@gmail.com>; MIT license
+
+// * feature-gated external crates
+#[cfg(all(feature = "lazy_static", target_os = "linux"))]
+extern crate lazy_static;
+#[cfg(feature = "nix")]
+extern crate nix;
+#[cfg(feature = "platform-info")]
+extern crate platform_info;
+
+// * feature-gated external crates (re-shared as public internal modules)
+#[cfg(feature = "libc")]
+pub extern crate libc;
+#[cfg(feature = "winapi")]
+pub extern crate winapi;
+
+//## internal modules
+
+mod features; // feature-gated code modules
+mod macros; // crate macros (macro_rules-type; exported to `crate::...`)
+mod mods; // core cross-platform modules
+mod parser; // string parsing modules
+
+// * cross-platform modules
+pub use crate::mods::backup_control;
+pub use crate::mods::coreopts;
+pub use crate::mods::error;
+pub use crate::mods::os;
+pub use crate::mods::panic;
+pub use crate::mods::ranges;
+pub use crate::mods::version_cmp;
+
+// * string parsing modules
+pub use crate::parser::parse_size;
+pub use crate::parser::parse_time;
+
+// * feature-gated modules
+#[cfg(feature = "encoding")]
+pub use crate::features::encoding;
+#[cfg(feature = "fs")]
+pub use crate::features::fs;
+#[cfg(feature = "fsext")]
+pub use crate::features::fsext;
+#[cfg(feature = "ringbuffer")]
+pub use crate::features::ringbuffer;
+#[cfg(feature = "zero-copy")]
+pub use crate::features::zero_copy;
+
+// * (platform-specific) feature-gated modules
+// ** non-windows
+#[cfg(all(not(windows), feature = "mode"))]
+pub use crate::features::mode;
+// ** unix-only
+#[cfg(all(unix, feature = "entries"))]
+pub use crate::features::entries;
+#[cfg(all(unix, feature = "perms"))]
+pub use crate::features::perms;
+#[cfg(all(unix, feature = "process"))]
+pub use crate::features::process;
+#[cfg(all(unix, not(target_os = "fuchsia"), feature = "signals"))]
+pub use crate::features::signals;
+#[cfg(all(
+    unix,
+    not(target_os = "fuchsia"),
+    not(target_os = "redox"),
+    not(target_env = "musl"),
+    feature = "utmpx"
+))]
+pub use crate::features::utmpx;
+// ** windows-only
+#[cfg(all(windows, feature = "wide"))]
+pub use crate::features::wide;
+
+//## core functions
+
+use std::ffi::OsString;
+use std::sync::atomic::Ordering;
+
+pub fn get_utility_is_second_arg() -> bool {
+    crate::macros::UTILITY_IS_SECOND_ARG.load(Ordering::SeqCst)
+}
+
+pub fn set_utility_is_second_arg() {
+    crate::macros::UTILITY_IS_SECOND_ARG.store(true, Ordering::SeqCst)
+}
+
+/// Get the executable path (as `OsString`).
+fn executable_os() -> OsString {
+    args_os().next().unwrap()
+}
+
+/// Get the executable path (as `String`).
+fn executable() -> String {
+    executable_os().to_string_lossy().into_owned()
+}
+
+/// Derive the utility name.
+pub fn util_name() -> String {
+    if get_utility_is_second_arg() {
+        args_os().nth(1).unwrap().to_string_lossy().into_owned()
+    } else {
+        executable()
+    }
+}
+
+/// Derive the complete execution phrase for "usage".
+pub fn execution_phrase() -> String {
+    if get_utility_is_second_arg() {
+        args_os()
+            .take(2)
+            .map(|os_str| os_str.to_string_lossy().into_owned())
+            .collect::<Vec<_>>()
+            .join(" ")
+    } else {
+        executable()
+    }
+}
+
+pub enum InvalidEncodingHandling {
+    Ignore,
+    ConvertLossy,
+    Panic,
+}
+
+#[must_use]
+pub enum ConversionResult {
+    Complete(Vec<String>),
+    Lossy(Vec<String>),
+}
+
+impl ConversionResult {
+    pub fn accept_any(self) -> Vec<String> {
+        match self {
+            Self::Complete(result) => result,
+            Self::Lossy(result) => result,
+        }
+    }
+
+    pub fn expect_lossy(self, msg: &str) -> Vec<String> {
+        match self {
+            Self::Lossy(result) => result,
+            Self::Complete(_) => {
+                panic!("{}", msg);
+            }
+        }
+    }
+
+    pub fn expect_complete(self, msg: &str) -> Vec<String> {
+        match self {
+            Self::Complete(result) => result,
+            Self::Lossy(_) => {
+                panic!("{}", msg);
+            }
+        }
+    }
+}
+
+pub trait Args: Iterator<Item = OsString> + Sized {
+    /// Converts each iterator item to a String and collects these into a vector
+    /// On invalid encoding, the result will depend on the argument. This method allows to either drop entries with illegal encoding
+    /// completely (```InvalidEncodingHandling::Ignore```), convert them using lossy-conversion (```InvalidEncodingHandling::Lossy```) which will
+    /// result in strange strings or can chosen to panic (```InvalidEncodingHandling::Panic```).
+    /// # Arguments
+    /// * `handling` - This switch allows to switch the behavior, when invalid encoding is encountered
+    /// # Panics
+    /// * Occurs, when invalid encoding is encountered and handling is set to ```InvalidEncodingHandling::Panic```
+    fn collect_str(self, handling: InvalidEncodingHandling) -> ConversionResult {
+        let mut full_conversion = true;
+        let result_vector: Vec<String> = self
+            .map(|s| match s.into_string() {
+                Ok(string) => Ok(string),
+                Err(s_ret) => {
+                    full_conversion = false;
+                    let lossy_conversion = s_ret.to_string_lossy();
+                    eprintln!(
+                        "Input with broken encoding occurred! (s = '{}') ",
+                        &lossy_conversion
+                    );
+                    match handling {
+                        InvalidEncodingHandling::Ignore => Err(String::new()),
+                        InvalidEncodingHandling::ConvertLossy => Err(lossy_conversion.to_string()),
+                        InvalidEncodingHandling::Panic => {
+                            panic!("Broken encoding found but caller cannot handle it")
+                        }
+                    }
+                }
+            })
+            .filter(|s| match handling {
+                InvalidEncodingHandling::Ignore => s.is_ok(),
+                _ => true,
+            })
+            .map(|s| match s {
+                Ok(v) => v,
+                Err(e) => e,
+            })
+            .collect();
+
+        if full_conversion {
+            ConversionResult::Complete(result_vector)
+        } else {
+            ConversionResult::Lossy(result_vector)
+        }
+    }
+
+    /// convenience function for a more slim interface
+    fn collect_str_lossy(self) -> ConversionResult {
+        self.collect_str(InvalidEncodingHandling::ConvertLossy)
+    }
+}
+
+impl<T: Iterator<Item = OsString> + Sized> Args for T {}
+
+// args() ...
+pub fn args() -> impl Iterator<Item = String> {
+    wild::args()
+}
+
+pub fn args_os() -> impl Iterator<Item = OsString> {
+    wild::args_os()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::ffi::OsStr;
+
+    fn make_os_vec(os_str: &OsStr) -> Vec<OsString> {
+        vec![
+            OsString::from("test"),
+            OsString::from("สวัสดี"), // spell-checker:disable-line
+            os_str.to_os_string(),
+        ]
+    }
+
+    fn collect_os_str(vec: Vec<OsString>, handling: InvalidEncodingHandling) -> ConversionResult {
+        vec.into_iter().collect_str(handling)
+    }
+
+    #[cfg(any(unix, target_os = "redox"))]
+    fn test_invalid_utf8_args_lossy(os_str: &OsStr) {
+        //assert our string is invalid utf8
+        assert!(os_str.to_os_string().into_string().is_err());
+        let test_vec = make_os_vec(os_str);
+        let collected_to_str =
+            collect_os_str(test_vec.clone(), InvalidEncodingHandling::ConvertLossy)
+                .expect_lossy("Lossy conversion expected in this test: bad encoding entries should be converted as good as possible");
+        //conservation of length - when accepting lossy conversion no arguments may be dropped
+        assert_eq!(collected_to_str.len(), test_vec.len());
+        //first indices identical
+        for index in 0..2 {
+            assert_eq!(
+                collected_to_str.get(index).unwrap(),
+                test_vec.get(index).unwrap().to_str().unwrap()
+            );
+        }
+        //lossy conversion for string with illegal encoding is done
+        assert_eq!(
+            *collected_to_str.get(2).unwrap(),
+            os_str.to_os_string().to_string_lossy()
+        );
+    }
+
+    #[cfg(any(unix, target_os = "redox"))]
+    fn test_invalid_utf8_args_ignore(os_str: &OsStr) {
+        //assert our string is invalid utf8
+        assert!(os_str.to_os_string().into_string().is_err());
+        let test_vec = make_os_vec(os_str);
+        let collected_to_str = collect_os_str(test_vec.clone(), InvalidEncodingHandling::Ignore)
+            .expect_lossy(
+                "Lossy conversion expected in this test: bad encoding entries should be filtered",
+            );
+        //assert that the broken entry is filtered out
+        assert_eq!(collected_to_str.len(), test_vec.len() - 1);
+        //assert that the unbroken indices are converted as expected
+        for index in 0..2 {
+            assert_eq!(
+                collected_to_str.get(index).unwrap(),
+                test_vec.get(index).unwrap().to_str().unwrap()
+            );
+        }
+    }
+
+    #[test]
+    fn valid_utf8_encoding_args() {
+        //create a vector containing only correct encoding
+        let test_vec = make_os_vec(&OsString::from("test2"));
+        //expect complete conversion without losses, even when lossy conversion is accepted
+        let _ = collect_os_str(test_vec, InvalidEncodingHandling::ConvertLossy)
+            .expect_complete("Lossy conversion not expected in this test");
+    }
+
+    #[cfg(any(unix, target_os = "redox"))]
+    #[test]
+    fn invalid_utf8_args_unix() {
+        use std::os::unix::ffi::OsStrExt;
+
+        let source = [0x66, 0x6f, 0x80, 0x6f];
+        let os_str = OsStr::from_bytes(&source[..]);
+        test_invalid_utf8_args_lossy(os_str);
+        test_invalid_utf8_args_ignore(os_str);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/macros.rs.html b/src/uucore/macros.rs.html new file mode 100644 index 000000000..4fba3b490 --- /dev/null +++ b/src/uucore/macros.rs.html @@ -0,0 +1,495 @@ +macros.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+
+use std::sync::atomic::AtomicBool;
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Alex Lyon <arcterus@mail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+/// Whether we were called as a multicall binary ("coreutils <utility>")
+pub static UTILITY_IS_SECOND_ARG: AtomicBool = AtomicBool::new(false);
+
+//====
+
+#[macro_export]
+macro_rules! show(
+    ($err:expr) => ({
+        let e = $err;
+        $crate::error::set_exit_code(e.code());
+        eprintln!("{}: {}", $crate::util_name(), e);
+    })
+);
+
+#[macro_export]
+macro_rules! show_if_err(
+    ($res:expr) => ({
+        if let Err(e) = $res {
+            show!(e);
+        }
+    })
+);
+
+/// Show an error to stderr in a similar style to GNU coreutils.
+#[macro_export]
+macro_rules! show_error(
+    ($($args:tt)+) => ({
+        eprint!("{}: ", $crate::util_name());
+        eprintln!($($args)+);
+    })
+);
+
+/// Show a warning to stderr in a similar style to GNU coreutils.
+#[macro_export]
+macro_rules! show_error_custom_description (
+    ($err:expr,$($args:tt)+) => ({
+        eprint!("{}: {}: ", $crate::util_name(), $err);
+        eprintln!($($args)+);
+    })
+);
+
+#[macro_export]
+macro_rules! show_warning(
+    ($($args:tt)+) => ({
+        eprint!("{}: warning: ", $crate::util_name());
+        eprintln!($($args)+);
+    })
+);
+
+/// Show a bad invocation help message in a similar style to GNU coreutils.
+#[macro_export]
+macro_rules! show_usage_error(
+    ($($args:tt)+) => ({
+        eprint!("{}: ", $crate::util_name());
+        eprintln!($($args)+);
+        eprintln!("Try '{} --help' for more information.", $crate::execution_phrase());
+    })
+);
+
+//====
+
+/// Calls `exit()` with the provided exit code.
+#[macro_export]
+macro_rules! exit(
+    ($exit_code:expr) => ({
+        ::std::process::exit($exit_code)
+    })
+);
+
+/// Display the provided error message, then `exit()` with the provided exit code
+#[macro_export]
+macro_rules! crash(
+    ($exit_code:expr, $($args:tt)+) => ({
+        $crate::show_error!($($args)+);
+        $crate::exit!($exit_code)
+    })
+);
+
+/// Unwraps the Result. Instead of panicking, it exists the program with the
+/// provided exit code.
+#[macro_export]
+macro_rules! crash_if_err(
+    ($exit_code:expr, $exp:expr) => (
+        match $exp {
+            Ok(m) => m,
+            Err(f) => $crate::crash!($exit_code, "{}", f),
+        }
+    )
+);
+
+//====
+
+/// Unwraps the Result. Instead of panicking, it shows the error and then
+/// returns from the function with the provided exit code.
+/// Assumes the current function returns an i32 value.
+#[macro_export]
+macro_rules! return_if_err(
+    ($exit_code:expr, $exp:expr) => (
+        match $exp {
+            Ok(m) => m,
+            Err(f) => {
+                $crate::show_error!("{}", f);
+                return $exit_code;
+            }
+        }
+    )
+);
+
+//====
+
+#[macro_export]
+macro_rules! safe_write(
+    ($fd:expr, $($args:tt)+) => (
+        match write!($fd, $($args)+) {
+            Ok(_) => {}
+            Err(f) => panic!("{}", f)
+        }
+    )
+);
+
+#[macro_export]
+macro_rules! safe_writeln(
+    ($fd:expr, $($args:tt)+) => (
+        match writeln!($fd, $($args)+) {
+            Ok(_) => {}
+            Err(f) => panic!("{}", f)
+        }
+    )
+);
+
+/// Unwraps the Result. Instead of panicking, it exists the program with exit
+/// code 1.
+#[macro_export]
+macro_rules! safe_unwrap(
+    ($exp:expr) => (
+        match $exp {
+            Ok(m) => m,
+            Err(f) => $crate::crash!(1, "{}", f.to_string())
+        }
+    )
+);
+
+//-- message templates
+
+//-- message templates : (join utility sub-macros)
+
+#[macro_export]
+macro_rules! snippet_list_join_oxford_comma {
+    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
+        format!("{}, {} {}", $valOne, $conjunction, $valTwo)
+    );
+    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
+        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
+    );
+}
+
+#[macro_export]
+macro_rules! snippet_list_join {
+    ($conjunction:expr, $valOne:expr, $valTwo:expr) => (
+        format!("{} {} {}", $valOne, $conjunction, $valTwo)
+    );
+    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => (
+        format!("{}, {}", $valOne, $crate::snippet_list_join_oxford_comma!($conjunction, $valTwo $(, $remaining_values)*))
+    );
+}
+
+//-- message templates : invalid input
+
+#[macro_export]
+macro_rules! msg_invalid_input {
+    ($reason: expr) => {
+        format!("invalid input: {}", $reason)
+    };
+}
+
+// -- message templates : invalid input : flag
+
+#[macro_export]
+macro_rules! msg_invalid_opt_use {
+    ($about:expr, $flag:expr) => {
+        $crate::msg_invalid_input!(format!("The '{}' option {}", $flag, $about))
+    };
+    ($about:expr, $long_flag:expr, $short_flag:expr) => {
+        $crate::msg_invalid_input!(format!(
+            "The '{}' ('{}') option {}",
+            $long_flag, $short_flag, $about
+        ))
+    };
+}
+
+#[macro_export]
+macro_rules! msg_opt_only_usable_if {
+    ($clause:expr, $flag:expr) => {
+        $crate::msg_invalid_opt_use!(format!("only usable if {}", $clause), $flag)
+    };
+    ($clause:expr, $long_flag:expr, $short_flag:expr) => {
+        $crate::msg_invalid_opt_use!(
+            format!("only usable if {}", $clause),
+            $long_flag,
+            $short_flag
+        )
+    };
+}
+
+#[macro_export]
+macro_rules! msg_opt_invalid_should_be {
+    ($expects:expr, $received:expr, $flag:expr) => {
+        $crate::msg_invalid_opt_use!(
+            format!("expects {}, but was provided {}", $expects, $received),
+            $flag
+        )
+    };
+    ($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => {
+        $crate::msg_invalid_opt_use!(
+            format!("expects {}, but was provided {}", $expects, $received),
+            $long_flag,
+            $short_flag
+        )
+    };
+}
+
+// -- message templates : invalid input : input combinations
+
+#[macro_export]
+macro_rules! msg_expects_one_of {
+    ($valOne:expr $(, $remaining_values:expr)*) => (
+        $crate::msg_invalid_input!(format!("expects one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*)))
+    );
+}
+
+#[macro_export]
+macro_rules! msg_expects_no_more_than_one_of {
+    ($valOne:expr $(, $remaining_values:expr)*) => (
+        $crate::msg_invalid_input!(format!("expects no more than one of {}", $crate::snippet_list_join!("or", $valOne $(, $remaining_values)*))) ;
+    );
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods.rs.html b/src/uucore/mods.rs.html new file mode 100644 index 000000000..9823b67d8 --- /dev/null +++ b/src/uucore/mods.rs.html @@ -0,0 +1,23 @@ +mods.rs - source + +
1
+2
+3
+4
+5
+6
+7
+8
+9
+
+// mods ~ cross-platforms modules (core/bundler file)
+
+pub mod backup_control;
+pub mod coreopts;
+pub mod error;
+pub mod os;
+pub mod panic;
+pub mod ranges;
+pub mod version_cmp;
+
+
\ No newline at end of file diff --git a/src/uucore/mods/backup_control.rs.html b/src/uucore/mods/backup_control.rs.html new file mode 100644 index 000000000..9a8a16fbe --- /dev/null +++ b/src/uucore/mods/backup_control.rs.html @@ -0,0 +1,915 @@ +backup_control.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+
+use std::{
+    env,
+    path::{Path, PathBuf},
+};
+
+pub static BACKUP_CONTROL_VALUES: &[&str] = &[
+    "simple", "never", "numbered", "t", "existing", "nil", "none", "off",
+];
+
+pub static BACKUP_CONTROL_LONG_HELP: &str =
+    "The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX.
+The version control method may be selected via the --backup option or through
+the VERSION_CONTROL environment variable.  Here are the values:
+
+  none, off       never make backups (even if --backup is given)
+  numbered, t     make numbered backups
+  existing, nil   numbered if numbered backups exist, simple otherwise
+  simple, never   always make simple backups";
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq)]
+pub enum BackupMode {
+    NoBackup,
+    SimpleBackup,
+    NumberedBackup,
+    ExistingBackup,
+}
+
+pub fn determine_backup_suffix(supplied_suffix: Option<&str>) -> String {
+    if let Some(suffix) = supplied_suffix {
+        String::from(suffix)
+    } else {
+        env::var("SIMPLE_BACKUP_SUFFIX").unwrap_or_else(|_| "~".to_owned())
+    }
+}
+
+/// Determine the "mode" for the backup operation to perform, if any.
+///
+/// Parses the backup options according to the [GNU manual][1], and converts
+/// them to an instance of `BackupMode` for further processing.
+///
+/// For an explanation of what the arguments mean, refer to the examples below.
+///
+/// [1]: https://www.gnu.org/software/coreutils/manual/html_node/Backup-options.html
+///
+///
+/// # Errors
+///
+/// If an argument supplied directly to the long `backup` option, or read in
+/// through the `VERSION CONTROL` env var is ambiguous (i.e. may resolve to
+/// multiple backup modes) or invalid, an error is returned. The error contains
+/// the formatted error string which may then be passed to the
+/// [`show_usage_error`] macro.
+///
+///
+/// # Examples
+///
+/// Here's how one would integrate the backup mode determination into an
+/// application.
+///
+/// ```
+/// #[macro_use]
+/// extern crate uucore;
+/// use uucore::backup_control::{self, BackupMode};
+/// use clap::{App, Arg};
+///
+/// fn main() {
+///     let OPT_BACKUP: &str = "backup";
+///     let OPT_BACKUP_NO_ARG: &str = "b";
+///     let matches = App::new("app")
+///         .arg(Arg::with_name(OPT_BACKUP_NO_ARG)
+///             .short(OPT_BACKUP_NO_ARG))
+///         .arg(Arg::with_name(OPT_BACKUP)
+///             .long(OPT_BACKUP)
+///             .takes_value(true)
+///             .require_equals(true)
+///             .min_values(0))
+///         .get_matches_from(vec![
+///             "app", "-b", "--backup=t"
+///         ]);
+///    
+///     let backup_mode = backup_control::determine_backup_mode(
+///         matches.is_present(OPT_BACKUP_NO_ARG), matches.is_present(OPT_BACKUP),
+///         matches.value_of(OPT_BACKUP)
+///     );
+///     let backup_mode = match backup_mode {
+///         Err(err) => {
+///             show_usage_error!("{}", err);
+///             return;
+///         },
+///         Ok(mode) => mode,
+///     };
+/// }
+/// ```
+///
+/// This example shows an ambiguous input, as 'n' may resolve to 4 different
+/// backup modes.
+///
+///
+/// ```
+/// #[macro_use]
+/// extern crate uucore;
+/// use uucore::backup_control::{self, BackupMode};
+/// use clap::{crate_version, App, Arg, ArgMatches};
+///
+/// fn main() {
+///     let OPT_BACKUP: &str = "backup";
+///     let OPT_BACKUP_NO_ARG: &str = "b";
+///     let matches = App::new("app")
+///         .arg(Arg::with_name(OPT_BACKUP_NO_ARG)
+///             .short(OPT_BACKUP_NO_ARG))
+///         .arg(Arg::with_name(OPT_BACKUP)
+///             .long(OPT_BACKUP)
+///             .takes_value(true)
+///             .require_equals(true)
+///             .min_values(0))
+///         .get_matches_from(vec![
+///             "app", "-b", "--backup=n"
+///         ]);
+///    
+///     let backup_mode = backup_control::determine_backup_mode(
+///         matches.is_present(OPT_BACKUP_NO_ARG), matches.is_present(OPT_BACKUP),
+///         matches.value_of(OPT_BACKUP)
+///     );
+///     let backup_mode = match backup_mode {
+///         Err(err) => {
+///             show_usage_error!("{}", err);
+///             return;
+///         },
+///         Ok(mode) => mode,
+///     };
+/// }
+/// ```
+pub fn determine_backup_mode(
+    short_opt_present: bool,
+    long_opt_present: bool,
+    long_opt_value: Option<&str>,
+) -> Result<BackupMode, String> {
+    if long_opt_present {
+        // Use method to determine the type of backups to make. When this option
+        // is used but method is not specified, then the value of the
+        // VERSION_CONTROL environment variable is used. And if VERSION_CONTROL
+        // is not set, the default backup type is ‘existing’.
+        if let Some(method) = long_opt_value {
+            // Second argument is for the error string that is returned.
+            match_method(method, "backup type")
+        } else if let Ok(method) = env::var("VERSION_CONTROL") {
+            // Second argument is for the error string that is returned.
+            match_method(&method, "$VERSION_CONTROL")
+        } else {
+            Ok(BackupMode::ExistingBackup)
+        }
+    } else if short_opt_present {
+        // the short form of this option, -b does not accept any argument.
+        // Using -b is equivalent to using --backup=existing.
+        Ok(BackupMode::ExistingBackup)
+    } else {
+        // No option was present at all
+        Ok(BackupMode::NoBackup)
+    }
+}
+
+/// Match a backup option string to a `BackupMode`.
+///
+/// The GNU manual specifies that abbreviations to options are valid as long as
+/// they aren't ambiguous. This function matches the given `method` argument
+/// against all valid backup options (via `starts_with`), and returns a valid
+/// [`BackupMode`] if exactly one backup option matches the `method` given.
+///
+/// `origin` is required in order to format the generated error message
+/// properly, when an error occurs.
+///
+///
+/// # Errors
+///
+/// If `method` is ambiguous (i.e. may resolve to multiple backup modes) or
+/// invalid, an error is returned. The error contains the formatted error string
+/// which may then be passed to the [`show_usage_error`] macro.
+fn match_method(method: &str, origin: &str) -> Result<BackupMode, String> {
+    let matches: Vec<&&str> = BACKUP_CONTROL_VALUES
+        .iter()
+        .filter(|val| val.starts_with(method))
+        .collect();
+    if matches.len() == 1 {
+        match *matches[0] {
+            "simple" | "never" => Ok(BackupMode::SimpleBackup),
+            "numbered" | "t" => Ok(BackupMode::NumberedBackup),
+            "existing" | "nil" => Ok(BackupMode::ExistingBackup),
+            "none" | "off" => Ok(BackupMode::NoBackup),
+            _ => unreachable!(), // cannot happen as we must have exactly one match
+                                 // from the list above.
+        }
+    } else {
+        let error_type = if matches.is_empty() {
+            "invalid"
+        } else {
+            "ambiguous"
+        };
+        Err(format!(
+            "{0} argument ‘{1}’ for ‘{2}’
+Valid arguments are:
+  - ‘none’, ‘off’
+  - ‘simple’, ‘never’
+  - ‘existing’, ‘nil’
+  - ‘numbered’, ‘t’",
+            error_type, method, origin
+        ))
+    }
+}
+
+pub fn get_backup_path(
+    backup_mode: BackupMode,
+    backup_path: &Path,
+    suffix: &str,
+) -> Option<PathBuf> {
+    match backup_mode {
+        BackupMode::NoBackup => None,
+        BackupMode::SimpleBackup => Some(simple_backup_path(backup_path, suffix)),
+        BackupMode::NumberedBackup => Some(numbered_backup_path(backup_path)),
+        BackupMode::ExistingBackup => Some(existing_backup_path(backup_path, suffix)),
+    }
+}
+
+fn simple_backup_path(path: &Path, suffix: &str) -> PathBuf {
+    let mut p = path.to_string_lossy().into_owned();
+    p.push_str(suffix);
+    PathBuf::from(p)
+}
+
+fn numbered_backup_path(path: &Path) -> PathBuf {
+    for i in 1_u64.. {
+        let path_str = &format!("{}.~{}~", path.to_string_lossy(), i);
+        let path = Path::new(path_str);
+        if !path.exists() {
+            return path.to_path_buf();
+        }
+    }
+    panic!("cannot create backup")
+}
+
+fn existing_backup_path(path: &Path, suffix: &str) -> PathBuf {
+    let test_path_str = &format!("{}.~1~", path.to_string_lossy());
+    let test_path = Path::new(test_path_str);
+    if test_path.exists() {
+        numbered_backup_path(path)
+    } else {
+        simple_backup_path(path, suffix)
+    }
+}
+
+//
+// Tests for this module
+//
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use std::env;
+    // Required to instantiate mutex in shared context
+    use lazy_static::lazy_static;
+    use std::sync::Mutex;
+
+    // The mutex is required here as by default all tests are run as separate
+    // threads under the same parent process. As environment variables are
+    // specific to processes (and thus shared among threads), data races *will*
+    // occur if no precautions are taken. Thus we have all tests that rely on
+    // environment variables lock this empty mutex to ensure they don't access
+    // it concurrently.
+    lazy_static! {
+        static ref TEST_MUTEX: Mutex<()> = Mutex::new(());
+    }
+
+    // Environment variable for "VERSION_CONTROL"
+    static ENV_VERSION_CONTROL: &str = "VERSION_CONTROL";
+
+    // Defaults to --backup=existing
+    #[test]
+    fn test_backup_mode_short_only() {
+        let short_opt_present = true;
+        let long_opt_present = false;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::ExistingBackup);
+    }
+
+    // --backup takes precedence over -b
+    #[test]
+    fn test_backup_mode_long_preferred_over_short() {
+        let short_opt_present = true;
+        let long_opt_present = true;
+        let long_opt_value = Some("none");
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::NoBackup);
+    }
+
+    // --backup can be passed without an argument
+    #[test]
+    fn test_backup_mode_long_without_args_no_env() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::ExistingBackup);
+    }
+
+    // --backup can be passed with an argument only
+    #[test]
+    fn test_backup_mode_long_with_args() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = Some("simple");
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::SimpleBackup);
+    }
+
+    // --backup errors on invalid argument
+    #[test]
+    fn test_backup_mode_long_with_args_invalid() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = Some("foobar");
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result = determine_backup_mode(short_opt_present, long_opt_present, long_opt_value);
+
+        assert!(result.is_err());
+        let text = result.unwrap_err();
+        assert!(text.contains("invalid argument ‘foobar’ for ‘backup type’"));
+    }
+
+    // --backup errors on ambiguous argument
+    #[test]
+    fn test_backup_mode_long_with_args_ambiguous() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = Some("n");
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result = determine_backup_mode(short_opt_present, long_opt_present, long_opt_value);
+
+        assert!(result.is_err());
+        let text = result.unwrap_err();
+        assert!(text.contains("ambiguous argument ‘n’ for ‘backup type’"));
+    }
+
+    // --backup accepts shortened arguments (si for simple)
+    #[test]
+    fn test_backup_mode_long_with_arg_shortened() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = Some("si");
+        let _dummy = TEST_MUTEX.lock().unwrap();
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::SimpleBackup);
+    }
+
+    // -b ignores the "VERSION_CONTROL" environment variable
+    #[test]
+    fn test_backup_mode_short_only_ignore_env() {
+        let short_opt_present = true;
+        let long_opt_present = false;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+        env::set_var(ENV_VERSION_CONTROL, "none");
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::ExistingBackup);
+        env::remove_var(ENV_VERSION_CONTROL);
+    }
+
+    // --backup can be passed without an argument, but reads env var if existent
+    #[test]
+    fn test_backup_mode_long_without_args_with_env() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+        env::set_var(ENV_VERSION_CONTROL, "none");
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::NoBackup);
+        env::remove_var(ENV_VERSION_CONTROL);
+    }
+
+    // --backup errors on invalid VERSION_CONTROL env var
+    #[test]
+    fn test_backup_mode_long_with_env_var_invalid() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+        env::set_var(ENV_VERSION_CONTROL, "foobar");
+
+        let result = determine_backup_mode(short_opt_present, long_opt_present, long_opt_value);
+
+        assert!(result.is_err());
+        let text = result.unwrap_err();
+        assert!(text.contains("invalid argument ‘foobar’ for ‘$VERSION_CONTROL’"));
+        env::remove_var(ENV_VERSION_CONTROL);
+    }
+
+    // --backup errors on ambiguous VERSION_CONTROL env var
+    #[test]
+    fn test_backup_mode_long_with_env_var_ambiguous() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+        env::set_var(ENV_VERSION_CONTROL, "n");
+
+        let result = determine_backup_mode(short_opt_present, long_opt_present, long_opt_value);
+
+        assert!(result.is_err());
+        let text = result.unwrap_err();
+        assert!(text.contains("ambiguous argument ‘n’ for ‘$VERSION_CONTROL’"));
+        env::remove_var(ENV_VERSION_CONTROL);
+    }
+
+    // --backup accepts shortened env vars (si for simple)
+    #[test]
+    fn test_backup_mode_long_with_env_var_shortened() {
+        let short_opt_present = false;
+        let long_opt_present = true;
+        let long_opt_value = None;
+        let _dummy = TEST_MUTEX.lock().unwrap();
+        env::set_var(ENV_VERSION_CONTROL, "si");
+
+        let result =
+            determine_backup_mode(short_opt_present, long_opt_present, long_opt_value).unwrap();
+
+        assert_eq!(result, BackupMode::SimpleBackup);
+        env::remove_var(ENV_VERSION_CONTROL);
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods/coreopts.rs.html b/src/uucore/mods/coreopts.rs.html new file mode 100644 index 000000000..d4386a408 --- /dev/null +++ b/src/uucore/mods/coreopts.rs.html @@ -0,0 +1,287 @@ +coreopts.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+
+pub struct HelpText<'a> {
+    pub name: &'a str,
+    pub version: &'a str,
+    pub syntax: &'a str,
+    pub summary: &'a str,
+    pub long_help: &'a str,
+    pub display_usage: bool,
+}
+
+pub struct CoreOptions<'a> {
+    options: getopts::Options,
+    help_text: HelpText<'a>,
+}
+
+impl<'a> CoreOptions<'a> {
+    pub fn new(help_text: HelpText<'a>) -> Self {
+        let mut ret = CoreOptions {
+            options: getopts::Options::new(),
+            help_text,
+        };
+        ret.options
+            .optflag("", "help", "print usage information")
+            .optflag("", "version", "print name and version number");
+        ret
+    }
+    pub fn optflagopt(
+        &mut self,
+        short_name: &str,
+        long_name: &str,
+        desc: &str,
+        hint: &str,
+    ) -> &mut CoreOptions<'a> {
+        self.options.optflagopt(short_name, long_name, desc, hint);
+        self
+    }
+    pub fn optflag(
+        &mut self,
+        short_name: &str,
+        long_name: &str,
+        desc: &str,
+    ) -> &mut CoreOptions<'a> {
+        self.options.optflag(short_name, long_name, desc);
+        self
+    }
+    pub fn optflagmulti(
+        &mut self,
+        short_name: &str,
+        long_name: &str,
+        desc: &str,
+    ) -> &mut CoreOptions<'a> {
+        self.options.optflagmulti(short_name, long_name, desc);
+        self
+    }
+    pub fn optopt(
+        &mut self,
+        short_name: &str,
+        long_name: &str,
+        desc: &str,
+        hint: &str,
+    ) -> &mut CoreOptions<'a> {
+        self.options.optopt(short_name, long_name, desc, hint);
+        self
+    }
+    pub fn optmulti(
+        &mut self,
+        short_name: &str,
+        long_name: &str,
+        desc: &str,
+        hint: &str,
+    ) -> &mut CoreOptions<'a> {
+        self.options.optmulti(short_name, long_name, desc, hint);
+        self
+    }
+    pub fn usage(&self, summary: &str) -> String {
+        self.options.usage(summary)
+    }
+    pub fn parse(&mut self, args: Vec<String>) -> getopts::Matches {
+        let matches = match self.options.parse(&args[1..]) {
+            Ok(m) => Some(m),
+            Err(f) => {
+                eprint!("{}: error: ", self.help_text.name);
+                eprintln!("{}", f);
+                ::std::process::exit(1);
+            }
+        }
+        .unwrap();
+        if matches.opt_present("help") {
+            let usage_str = if self.help_text.display_usage {
+                format!(
+                    "\n {}\n\n Reference\n",
+                    self.options.usage(self.help_text.summary)
+                )
+                .replace("Options:", " Options:")
+            } else {
+                String::new()
+            };
+            print!(
+                "
+ {0} {1}
+
+ {0} {2}
+{3}{4}
+",
+                self.help_text.name,
+                self.help_text.version,
+                self.help_text.syntax,
+                usage_str,
+                self.help_text.long_help
+            );
+            crate::exit!(0);
+        } else if matches.opt_present("version") {
+            println!("{} {}", self.help_text.name, self.help_text.version);
+            crate::exit!(0);
+        }
+        matches
+    }
+}
+
+#[macro_export]
+macro_rules! app {
+    ($syntax: expr, $summary: expr, $long_help: expr) => {
+        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
+            name: uucore::util_name(),
+            version: env!("CARGO_PKG_VERSION"),
+            syntax: $syntax,
+            summary: $summary,
+            long_help: $long_help,
+            display_usage: true,
+        })
+    };
+    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => {
+        uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
+            name: uucore::util_name(),
+            version: env!("CARGO_PKG_VERSION"),
+            syntax: $syntax,
+            summary: $summary,
+            long_help: $long_help,
+            display_usage: $display_usage,
+        })
+    };
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods/error.rs.html b/src/uucore/mods/error.rs.html new file mode 100644 index 000000000..d320c46fd --- /dev/null +++ b/src/uucore/mods/error.rs.html @@ -0,0 +1,1107 @@ +error.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+
+//! All utils return exit with an exit code. Usually, the following scheme is used:
+//! * `0`: succeeded
+//! * `1`: minor problems
+//! * `2`: major problems
+//!
+//! This module provides types to reconcile these exit codes with idiomatic Rust error
+//! handling. This has a couple advantages over manually using [`std::process::exit`]:
+//! 1. It enables the use of `?`, `map_err`, `unwrap_or`, etc. in `uumain`.
+//! 1. It encourages the use of [`UResult`]/[`Result`] in functions in the utils.
+//! 1. The error messages are largely standardized across utils.
+//! 1. Standardized error messages can be created from external result types
+//!    (i.e. [`std::io::Result`] & `clap::ClapResult`).
+//! 1. [`set_exit_code`] takes away the burden of manually tracking exit codes for non-fatal errors.
+//!
+//! # Usage
+//! The signature of a typical util should be:
+//! ```ignore
+//! fn uumain(args: impl uucore::Args) -> UResult<()> {
+//!     ...
+//! }
+//! ```
+//! [`UResult`] is a simple wrapper around [`Result`] with a custom error trait: [`UError`]. The
+//! most important difference with types implementing [`std::error::Error`] is that [`UError`]s
+//! can specify the exit code of the program when they are returned from `uumain`:
+//! * When `Ok` is returned, the code set with [`set_exit_code`] is used as exit code. If
+//!   [`set_exit_code`] was not used, then `0` is used.
+//! * When `Err` is returned, the code corresponding with the error is used as exit code and the
+//! error message is displayed.
+//!
+//! Additionally, the errors can be displayed manually with the [`show`] and [`show_if_err`] macros:
+//! ```ignore
+//! let res = Err(USimpleError::new(1, "Error!!"));
+//! show_if_err!(res);
+//! // or
+//! if let Err(e) = res {
+//!    show!(e);
+//! }
+//! ```
+//!
+//! **Note**: The [`show`] and [`show_if_err`] macros set the exit code of the program using
+//! [`set_exit_code`]. See the documentation on that function for more information.
+//!
+//! # Guidelines
+//! * Use error types from `uucore` where possible.
+//! * Add error types to `uucore` if an error appears in multiple utils.
+//! * Prefer proper custom error types over [`ExitCode`] and [`USimpleError`].
+//! * [`USimpleError`] may be used in small utils with simple error handling.
+//! * Using [`ExitCode`] is not recommended but can be useful for converting utils to use
+//!   [`UResult`].
+
+// spell-checker:ignore uioerror
+
+use std::{
+    error::Error,
+    fmt::{Display, Formatter},
+    sync::atomic::{AtomicI32, Ordering},
+};
+
+static EXIT_CODE: AtomicI32 = AtomicI32::new(0);
+
+/// Get the last exit code set with [`set_exit_code`].
+/// The default value is `0`.
+pub fn get_exit_code() -> i32 {
+    EXIT_CODE.load(Ordering::SeqCst)
+}
+
+/// Set the exit code for the program if `uumain` returns `Ok(())`.
+///
+/// This function is most useful for non-fatal errors, for example when applying an operation to
+/// multiple files:
+/// ```ignore
+/// use uucore::error::{UResult, set_exit_code};
+///
+/// fn uumain(args: impl uucore::Args) -> UResult<()> {
+///     ...
+///     for file in files {
+///         let res = some_operation_that_might_fail(file);
+///         match res {
+///             Ok() => {},
+///             Err(_) => set_exit_code(1),
+///         }
+///     }
+///     Ok(()) // If any of the operations failed, 1 is returned.
+/// }
+/// ```
+pub fn set_exit_code(code: i32) {
+    EXIT_CODE.store(code, Ordering::SeqCst);
+}
+
+/// Result type that should be returned by all utils.
+pub type UResult<T> = Result<T, Box<dyn UError>>;
+
+/// Custom errors defined by the utils and `uucore`.
+///
+/// All errors should implement [`std::error::Error`], [`std::fmt::Display`] and
+/// [`std::fmt::Debug`] and have an additional `code` method that specifies the
+/// exit code of the program if the error is returned from `uumain`.
+///
+/// An example of a custom error from `ls`:
+///
+/// ```
+/// use uucore::error::{UError, UResult};
+/// use std::{
+///     error::Error,
+///     fmt::{Display, Debug},
+///     path::PathBuf
+/// };
+///
+/// #[derive(Debug)]
+/// enum LsError {
+///     InvalidLineWidth(String),
+///     NoMetadata(PathBuf),
+/// }
+///
+/// impl UError for LsError {
+///     fn code(&self) -> i32 {
+///         match self {
+///             LsError::InvalidLineWidth(_) => 2,
+///             LsError::NoMetadata(_) => 1,
+///         }
+///     }
+/// }
+///
+/// impl Error for LsError {}
+///
+/// impl Display for LsError {
+///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+///         match self {
+///             LsError::InvalidLineWidth(s) => write!(f, "invalid line width: '{}'", s),
+///             LsError::NoMetadata(p) => write!(f, "could not open file: '{}'", p.display()),
+///         }
+///     }
+/// }
+/// ```
+///
+/// The main routine would look like this:
+///
+/// ```ignore
+/// #[uucore_procs::gen_uumain]
+/// pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+///     // Perform computations here ...
+///     return Err(LsError::InvalidLineWidth(String::from("test")).into())
+/// }
+/// ```
+///
+/// The call to `into()` is required to convert the `LsError` to
+/// [`Box<dyn UError>`]. The implementation for `From` is provided automatically.
+///
+/// A crate like [`quick_error`](https://crates.io/crates/quick-error) might
+/// also be used, but will still require an `impl` for the `code` method.
+pub trait UError: Error + Send {
+    /// Error code of a custom error.
+    ///
+    /// Set a return value for each variant of an enum-type to associate an
+    /// error code (which is returned to the system shell) with an error
+    /// variant.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use uucore::error::{UError};
+    /// use std::{
+    ///     error::Error,
+    ///     fmt::{Display, Debug},
+    ///     path::PathBuf
+    /// };
+    ///
+    /// #[derive(Debug)]
+    /// enum MyError {
+    ///     Foo(String),
+    ///     Bar(PathBuf),
+    ///     Bing(),
+    /// }
+    ///
+    /// impl UError for MyError {
+    ///     fn code(&self) -> i32 {
+    ///         match self {
+    ///             MyError::Foo(_) => 2,
+    ///             // All other errors yield the same error code, there's no
+    ///             // need to list them explicitly.
+    ///             _ => 1,
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// impl Error for MyError {}
+    ///
+    /// impl Display for MyError {
+    ///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    ///         use MyError as ME;
+    ///         match self {
+    ///             ME::Foo(s) => write!(f, "Unknown Foo: '{}'", s),
+    ///             ME::Bar(p) => write!(f, "Couldn't find Bar: '{}'", p.display()),
+    ///             ME::Bing() => write!(f, "Exterminate!"),
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    fn code(&self) -> i32 {
+        1
+    }
+
+    /// Print usage help to a custom error.
+    ///
+    /// Return true or false to control whether a short usage help is printed
+    /// below the error message. The usage help is in the format: "Try `{name}
+    /// --help` for more information." and printed only if `true` is returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// use uucore::error::{UError};
+    /// use std::{
+    ///     error::Error,
+    ///     fmt::{Display, Debug},
+    ///     path::PathBuf
+    /// };
+    ///
+    /// #[derive(Debug)]
+    /// enum MyError {
+    ///     Foo(String),
+    ///     Bar(PathBuf),
+    ///     Bing(),
+    /// }
+    ///
+    /// impl UError for MyError {
+    ///     fn usage(&self) -> bool {
+    ///         match self {
+    ///             // This will have a short usage help appended
+    ///             MyError::Bar(_) => true,
+    ///             // These matches won't have a short usage help appended
+    ///             _ => false,
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// impl Error for MyError {}
+    ///
+    /// impl Display for MyError {
+    ///     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+    ///         use MyError as ME;
+    ///         match self {
+    ///             ME::Foo(s) => write!(f, "Unknown Foo: '{}'", s),
+    ///             ME::Bar(p) => write!(f, "Couldn't find Bar: '{}'", p.display()),
+    ///             ME::Bing() => write!(f, "Exterminate!"),
+    ///         }
+    ///     }
+    /// }
+    /// ```
+    fn usage(&self) -> bool {
+        false
+    }
+}
+
+impl<T> From<T> for Box<dyn UError>
+where
+    T: UError + 'static,
+{
+    fn from(t: T) -> Box<dyn UError> {
+        Box::new(t)
+    }
+}
+
+/// A simple error type with an exit code and a message that implements [`UError`].
+///
+/// ```
+/// use uucore::error::{UResult, USimpleError};
+/// let err = USimpleError { code: 1, message: "error!".into()};
+/// let res: UResult<()> = Err(err.into());
+/// // or using the `new` method:
+/// let res: UResult<()> = Err(USimpleError::new(1, "error!"));
+/// ```
+#[derive(Debug)]
+pub struct USimpleError {
+    pub code: i32,
+    pub message: String,
+}
+
+impl USimpleError {
+    #[allow(clippy::new_ret_no_self)]
+    pub fn new<S: Into<String>>(code: i32, message: S) -> Box<dyn UError> {
+        Box::new(Self {
+            code,
+            message: message.into(),
+        })
+    }
+}
+
+impl Error for USimpleError {}
+
+impl Display for USimpleError {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+        self.message.fmt(f)
+    }
+}
+
+impl UError for USimpleError {
+    fn code(&self) -> i32 {
+        self.code
+    }
+}
+
+#[derive(Debug)]
+pub struct UUsageError {
+    pub code: i32,
+    pub message: String,
+}
+
+impl UUsageError {
+    #[allow(clippy::new_ret_no_self)]
+    pub fn new<S: Into<String>>(code: i32, message: S) -> Box<dyn UError> {
+        Box::new(Self {
+            code,
+            message: message.into(),
+        })
+    }
+}
+
+impl Error for UUsageError {}
+
+impl Display for UUsageError {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+        self.message.fmt(f)
+    }
+}
+
+impl UError for UUsageError {
+    fn code(&self) -> i32 {
+        self.code
+    }
+
+    fn usage(&self) -> bool {
+        true
+    }
+}
+
+/// Wrapper type around [`std::io::Error`].
+///
+/// The messages displayed by [`UIoError`] should match the error messages displayed by GNU
+/// coreutils.
+///
+/// There are two ways to construct this type: with [`UIoError::new`] or by calling the
+/// [`FromIo::map_err_context`] method on a [`std::io::Result`] or [`std::io::Error`].
+/// ```
+/// use uucore::error::{FromIo, UResult, UIoError, UError};
+/// use std::fs::File;
+/// use std::path::Path;
+/// let path = Path::new("test.txt");
+///
+/// // Manual construction
+/// let e: Box<dyn UError> = UIoError::new(
+///     std::io::ErrorKind::NotFound,
+///     format!("cannot access '{}'", path.display())
+/// );
+/// let res: UResult<()> = Err(e.into());
+///
+/// // Converting from an `std::io::Error`.
+/// let res: UResult<File> = File::open(path).map_err_context(|| format!("cannot access '{}'", path.display()));
+/// ```
+#[derive(Debug)]
+pub struct UIoError {
+    context: String,
+    inner: std::io::Error,
+}
+
+impl UIoError {
+    #[allow(clippy::new_ret_no_self)]
+    pub fn new<S: Into<String>>(kind: std::io::ErrorKind, context: S) -> Box<dyn UError> {
+        Box::new(Self {
+            context: context.into(),
+            inner: std::io::Error::new(kind, ""),
+        })
+    }
+}
+
+impl UError for UIoError {}
+
+impl Error for UIoError {}
+
+impl Display for UIoError {
+    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+        use std::io::ErrorKind::*;
+        write!(
+            f,
+            "{}: {}",
+            self.context,
+            match self.inner.kind() {
+                NotFound => "No such file or directory",
+                PermissionDenied => "Permission denied",
+                ConnectionRefused => "Connection refused",
+                ConnectionReset => "Connection reset",
+                ConnectionAborted => "Connection aborted",
+                NotConnected => "Not connected",
+                AddrInUse => "Address in use",
+                AddrNotAvailable => "Address not available",
+                BrokenPipe => "Broken pipe",
+                AlreadyExists => "Already exists",
+                WouldBlock => "Would block",
+                InvalidInput => "Invalid input",
+                InvalidData => "Invalid data",
+                TimedOut => "Timed out",
+                WriteZero => "Write zero",
+                Interrupted => "Interrupted",
+                Other => "Other",
+                UnexpectedEof => "Unexpected end of file",
+                _ => panic!("Unexpected io error: {}", self.inner),
+            },
+        )
+    }
+}
+
+/// Enables the conversion from [`std::io::Error`] to [`UError`] and from [`std::io::Result`] to
+/// [`UResult`].
+pub trait FromIo<T> {
+    fn map_err_context(self, context: impl FnOnce() -> String) -> T;
+}
+
+impl FromIo<Box<UIoError>> for std::io::Error {
+    fn map_err_context(self, context: impl FnOnce() -> String) -> Box<UIoError> {
+        Box::new(UIoError {
+            context: (context)(),
+            inner: self,
+        })
+    }
+}
+
+impl<T> FromIo<UResult<T>> for std::io::Result<T> {
+    fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
+        self.map_err(|e| e.map_err_context(context) as Box<dyn UError>)
+    }
+}
+
+impl FromIo<Box<UIoError>> for std::io::ErrorKind {
+    fn map_err_context(self, context: impl FnOnce() -> String) -> Box<UIoError> {
+        Box::new(UIoError {
+            context: (context)(),
+            inner: std::io::Error::new(self, ""),
+        })
+    }
+}
+
+/// Shorthand to construct [`UIoError`]-instances.
+///
+/// This macro serves as a convenience call to quickly construct instances of
+/// [`UIoError`]. It takes:
+///
+/// - An instance of [`std::io::Error`]
+/// - A `format!`-compatible string and
+/// - An arbitrary number of arguments to the format string
+///
+/// In exactly this order. It is equivalent to the more verbose code seen in the
+/// example.
+///
+/// # Examples
+///
+/// ```
+/// use uucore::error::UIoError;
+/// use uucore::uio_error;
+///
+/// let io_err = std::io::Error::new(
+///     std::io::ErrorKind::PermissionDenied, "fix me please!"
+/// );
+///
+/// let uio_err = UIoError::new(
+///     io_err.kind(),
+///     format!("Error code: {}", 2)
+/// );
+///
+/// let other_uio_err = uio_error!(io_err, "Error code: {}", 2);
+///
+/// // prints "fix me please!: Permission denied"
+/// println!("{}", uio_err);
+/// // prints "Error code: 2: Permission denied"
+/// println!("{}", other_uio_err);
+/// ```
+///
+/// The [`std::fmt::Display`] impl of [`UIoError`] will then ensure that an
+/// appropriate error message relating to the actual error kind of the
+/// [`std::io::Error`] is appended to whatever error message is defined in
+/// addition (as secondary argument).
+///
+/// If you want to show only the error message for the [`std::io::ErrorKind`]
+/// that's contained in [`UIoError`], pass the second argument as empty string:
+///
+/// ```
+/// use uucore::error::UIoError;
+/// use uucore::uio_error;
+///
+/// let io_err = std::io::Error::new(
+///     std::io::ErrorKind::PermissionDenied, "fix me please!"
+/// );
+///
+/// let other_uio_err = uio_error!(io_err, "");
+///
+/// // prints: ": Permission denied"
+/// println!("{}", other_uio_err);
+/// ```
+//#[macro_use]
+#[macro_export]
+macro_rules! uio_error(
+    ($err:expr, $($args:tt)+) => ({
+        UIoError::new(
+            $err.kind(),
+            format!($($args)+)
+        )
+    })
+);
+
+/// A special error type that does not print any message when returned from
+/// `uumain`. Especially useful for porting utilities to using [`UResult`].
+///
+/// There are two ways to construct an [`ExitCode`]:
+/// ```
+/// use uucore::error::{ExitCode, UResult};
+/// // Explicit
+/// let res: UResult<()> = Err(ExitCode(1).into());
+///
+/// // Using into on `i32`:
+/// let res: UResult<()> = Err(1.into());
+/// ```
+/// This type is especially useful for a trivial conversion from utils returning [`i32`] to
+/// returning [`UResult`].
+#[derive(Debug)]
+pub struct ExitCode(pub i32);
+
+impl ExitCode {
+    #[allow(clippy::new_ret_no_self)]
+    pub fn new(code: i32) -> Box<dyn UError> {
+        Box::new(Self(code))
+    }
+}
+
+impl Error for ExitCode {}
+
+impl Display for ExitCode {
+    fn fmt(&self, _: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
+        Ok(())
+    }
+}
+
+impl UError for ExitCode {
+    fn code(&self) -> i32 {
+        self.0
+    }
+}
+
+impl From<i32> for Box<dyn UError> {
+    fn from(i: i32) -> Self {
+        ExitCode::new(i)
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods/os.rs.html b/src/uucore/mods/os.rs.html new file mode 100644 index 000000000..2c7f1a476 --- /dev/null +++ b/src/uucore/mods/os.rs.html @@ -0,0 +1,71 @@ +os.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+
+/// Test if the program is running under WSL
+// ref: <https://github.com/microsoft/WSL/issues/4555> @@ <https://archive.is/dP0bz>
+
+// spell-checker:ignore (path) osrelease
+
+pub fn is_wsl_1() -> bool {
+    #[cfg(target_os = "linux")]
+    {
+        if is_wsl_2() {
+            return false;
+        }
+        if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") {
+            if let Ok(s) = std::str::from_utf8(&b) {
+                let a = s.to_ascii_lowercase();
+                return a.contains("microsoft") || a.contains("wsl");
+            }
+        }
+    }
+    false
+}
+
+pub fn is_wsl_2() -> bool {
+    #[cfg(target_os = "linux")]
+    {
+        if let Ok(b) = std::fs::read("/proc/sys/kernel/osrelease") {
+            if let Ok(s) = std::str::from_utf8(&b) {
+                let a = s.to_ascii_lowercase();
+                return a.contains("wsl2");
+            }
+        }
+    }
+    false
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods/panic.rs.html b/src/uucore/mods/panic.rs.html new file mode 100644 index 000000000..4558bcb13 --- /dev/null +++ b/src/uucore/mods/panic.rs.html @@ -0,0 +1,39 @@ +panic.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+
+use std::panic;
+
+//## SIGPIPE handling background/discussions ...
+//* `uutils` ~ <https://github.com/uutils/coreutils/issues/374> , <https://github.com/uutils/coreutils/pull/1106>
+//* rust and `rg` ~ <https://github.com/rust-lang/rust/issues/62569> , <https://github.com/BurntSushi/ripgrep/issues/200> , <https://github.com/crev-dev/cargo-crev/issues/287>
+
+pub fn mute_sigpipe_panic() {
+    let hook = panic::take_hook();
+    panic::set_hook(Box::new(move |info| {
+        if let Some(res) = info.payload().downcast_ref::<String>() {
+            if res.contains("BrokenPipe") {
+                return;
+            }
+        }
+        hook(info)
+    }));
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods/ranges.rs.html b/src/uucore/mods/ranges.rs.html new file mode 100644 index 000000000..8edd0e1fb --- /dev/null +++ b/src/uucore/mods/ranges.rs.html @@ -0,0 +1,351 @@ +ranges.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Rolf Morel <rolfmorel@gmail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) inval
+
+use std::str::FromStr;
+
+#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
+pub struct Range {
+    pub low: usize,
+    pub high: usize,
+}
+
+impl FromStr for Range {
+    type Err = &'static str;
+
+    fn from_str(s: &str) -> Result<Range, &'static str> {
+        use std::usize::MAX;
+
+        let mut parts = s.splitn(2, '-');
+
+        let field = "fields and positions are numbered from 1";
+        let order = "high end of range less than low end";
+        let inval = "failed to parse range";
+
+        match (parts.next(), parts.next()) {
+            (Some(nm), None) => {
+                if let Ok(nm) = nm.parse::<usize>() {
+                    if nm > 0 {
+                        Ok(Range { low: nm, high: nm })
+                    } else {
+                        Err(field)
+                    }
+                } else {
+                    Err(inval)
+                }
+            }
+            (Some(n), Some(m)) if m.is_empty() => {
+                if let Ok(low) = n.parse::<usize>() {
+                    if low > 0 {
+                        Ok(Range { low, high: MAX - 1 })
+                    } else {
+                        Err(field)
+                    }
+                } else {
+                    Err(inval)
+                }
+            }
+            (Some(n), Some(m)) if n.is_empty() => {
+                if let Ok(high) = m.parse::<usize>() {
+                    if high > 0 {
+                        Ok(Range { low: 1, high })
+                    } else {
+                        Err(field)
+                    }
+                } else {
+                    Err(inval)
+                }
+            }
+            (Some(n), Some(m)) => match (n.parse::<usize>(), m.parse::<usize>()) {
+                (Ok(low), Ok(high)) => {
+                    if low > 0 && low <= high {
+                        Ok(Range { low, high })
+                    } else if low == 0 {
+                        Err(field)
+                    } else {
+                        Err(order)
+                    }
+                }
+                _ => Err(inval),
+            },
+            _ => unreachable!(),
+        }
+    }
+}
+
+impl Range {
+    pub fn from_list(list: &str) -> Result<Vec<Range>, String> {
+        use std::cmp::max;
+
+        let mut ranges: Vec<Range> = vec![];
+
+        for item in list.split(',') {
+            let range_item = FromStr::from_str(item)
+                .map_err(|e| format!("range '{}' was invalid: {}", item, e))?;
+            ranges.push(range_item);
+        }
+
+        ranges.sort();
+
+        // merge overlapping ranges
+        for i in 0..ranges.len() {
+            let j = i + 1;
+
+            while j < ranges.len() && ranges[j].low <= ranges[i].high {
+                let j_high = ranges.remove(j).high;
+                ranges[i].high = max(ranges[i].high, j_high);
+            }
+        }
+
+        Ok(ranges)
+    }
+}
+
+pub fn complement(ranges: &[Range]) -> Vec<Range> {
+    use std::usize;
+
+    let mut complements = Vec::with_capacity(ranges.len() + 1);
+
+    if !ranges.is_empty() && ranges[0].low > 1 {
+        complements.push(Range {
+            low: 1,
+            high: ranges[0].low - 1,
+        });
+    }
+
+    let mut ranges_iter = ranges.iter().peekable();
+    loop {
+        match (ranges_iter.next(), ranges_iter.peek()) {
+            (Some(left), Some(right)) => {
+                if left.high + 1 != right.low {
+                    complements.push(Range {
+                        low: left.high + 1,
+                        high: right.low - 1,
+                    });
+                }
+            }
+            (Some(last), None) => {
+                if last.high < usize::MAX - 1 {
+                    complements.push(Range {
+                        low: last.high + 1,
+                        high: usize::MAX - 1,
+                    });
+                }
+            }
+            _ => break,
+        }
+    }
+
+    complements
+}
+
+/// Test if at least one of the given Ranges contain the supplied value.
+///
+/// Examples:
+///
+/// ```
+/// let ranges = uucore::ranges::Range::from_list("11,2,6-8").unwrap();
+///
+/// assert!(!uucore::ranges::contain(&ranges, 0));
+/// assert!(!uucore::ranges::contain(&ranges, 1));
+/// assert!(!uucore::ranges::contain(&ranges, 5));
+/// assert!(!uucore::ranges::contain(&ranges, 10));
+///
+/// assert!(uucore::ranges::contain(&ranges, 2));
+/// assert!(uucore::ranges::contain(&ranges, 6));
+/// assert!(uucore::ranges::contain(&ranges, 7));
+/// assert!(uucore::ranges::contain(&ranges, 8));
+/// assert!(uucore::ranges::contain(&ranges, 11));
+/// ```
+pub fn contain(ranges: &[Range], n: usize) -> bool {
+    for range in ranges {
+        if n >= range.low && n <= range.high {
+            return true;
+        }
+    }
+
+    false
+}
+
+
\ No newline at end of file diff --git a/src/uucore/mods/version_cmp.rs.html b/src/uucore/mods/version_cmp.rs.html new file mode 100644 index 000000000..1bbf83d4c --- /dev/null +++ b/src/uucore/mods/version_cmp.rs.html @@ -0,0 +1,727 @@ +version_cmp.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+
+use std::cmp::Ordering;
+
+/// Compares the non-digit parts of a version.
+/// Special cases: ~ are before everything else, even ends ("a~" < "a")
+/// Letters are before non-letters
+fn version_non_digit_cmp(a: &str, b: &str) -> Ordering {
+    let mut a_chars = a.chars();
+    let mut b_chars = b.chars();
+    loop {
+        match (a_chars.next(), b_chars.next()) {
+            (Some(c1), Some(c2)) if c1 == c2 => {}
+            (None, None) => return Ordering::Equal,
+            (_, Some('~')) => return Ordering::Greater,
+            (Some('~'), _) => return Ordering::Less,
+            (None, Some(_)) => return Ordering::Less,
+            (Some(_), None) => return Ordering::Greater,
+            (Some(c1), Some(c2)) if c1.is_ascii_alphabetic() && !c2.is_ascii_alphabetic() => {
+                return Ordering::Less
+            }
+            (Some(c1), Some(c2)) if !c1.is_ascii_alphabetic() && c2.is_ascii_alphabetic() => {
+                return Ordering::Greater
+            }
+            (Some(c1), Some(c2)) => return c1.cmp(&c2),
+        }
+    }
+}
+
+/// Remove file endings matching the regex (\.[A-Za-z~][A-Za-z0-9~]*)*$
+fn remove_file_ending(a: &str) -> &str {
+    let mut ending_start = None;
+    let mut prev_was_dot = false;
+    for (idx, char) in a.char_indices() {
+        if char == '.' {
+            if ending_start.is_none() || prev_was_dot {
+                ending_start = Some(idx);
+            }
+            prev_was_dot = true;
+        } else if prev_was_dot {
+            prev_was_dot = false;
+            if !char.is_ascii_alphabetic() && char != '~' {
+                ending_start = None;
+            }
+        } else if !char.is_ascii_alphanumeric() && char != '~' {
+            ending_start = None;
+        }
+    }
+    if prev_was_dot {
+        ending_start = None;
+    }
+    if let Some(ending_start) = ending_start {
+        &a[..ending_start]
+    } else {
+        a
+    }
+}
+
+pub fn version_cmp(mut a: &str, mut b: &str) -> Ordering {
+    let str_cmp = a.cmp(b);
+    if str_cmp == Ordering::Equal {
+        return str_cmp;
+    }
+
+    // Special cases:
+    // 1. Empty strings
+    match (a.is_empty(), b.is_empty()) {
+        (true, false) => return Ordering::Less,
+        (false, true) => return Ordering::Greater,
+        (true, true) => unreachable!(),
+        (false, false) => {}
+    }
+    // 2. Dots
+    match (a == ".", b == ".") {
+        (true, false) => return Ordering::Less,
+        (false, true) => return Ordering::Greater,
+        (true, true) => unreachable!(),
+        (false, false) => {}
+    }
+    // 3. Two Dots
+    match (a == "..", b == "..") {
+        (true, false) => return Ordering::Less,
+        (false, true) => return Ordering::Greater,
+        (true, true) => unreachable!(),
+        (false, false) => {}
+    }
+    // 4. Strings starting with a dot
+    match (a.starts_with('.'), b.starts_with('.')) {
+        (true, false) => return Ordering::Less,
+        (false, true) => return Ordering::Greater,
+        (true, true) => {
+            // Strip the leading dot for later comparisons
+            a = &a[1..];
+            b = &b[1..];
+        }
+        _ => {}
+    }
+
+    // Try to strip file extensions
+    let (mut a, mut b) = match (remove_file_ending(a), remove_file_ending(b)) {
+        (a_stripped, b_stripped) if a_stripped == b_stripped => {
+            // If both would be the same after stripping file extensions, don't strip them.
+            (a, b)
+        }
+        stripped => stripped,
+    };
+
+    // 1. Compare leading non-numerical part
+    // 2. Compare leading numerical part
+    // 3. Repeat
+    loop {
+        let a_numerical_start = a.find(|c: char| c.is_ascii_digit()).unwrap_or(a.len());
+        let b_numerical_start = b.find(|c: char| c.is_ascii_digit()).unwrap_or(b.len());
+
+        let a_str = &a[..a_numerical_start];
+        let b_str = &b[..b_numerical_start];
+
+        match version_non_digit_cmp(a_str, b_str) {
+            Ordering::Equal => {}
+            ord => return ord,
+        }
+
+        a = &a[a_numerical_start..];
+        b = &b[a_numerical_start..];
+
+        let a_numerical_end = a.find(|c: char| !c.is_ascii_digit()).unwrap_or(a.len());
+        let b_numerical_end = b.find(|c: char| !c.is_ascii_digit()).unwrap_or(b.len());
+
+        let a_str = a[..a_numerical_end].trim_start_matches('0');
+        let b_str = b[..b_numerical_end].trim_start_matches('0');
+
+        match a_str.len().cmp(&b_str.len()) {
+            Ordering::Equal => {}
+            ord => return ord,
+        }
+
+        match a_str.cmp(b_str) {
+            Ordering::Equal => {}
+            ord => return ord,
+        }
+
+        a = &a[a_numerical_end..];
+        b = &b[b_numerical_end..];
+
+        if a.is_empty() && b.is_empty() {
+            // Default to the lexical comparison.
+            return str_cmp;
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::version_cmp::version_cmp;
+    use std::cmp::Ordering;
+    #[test]
+    fn test_version_cmp() {
+        // Identical strings
+        assert_eq!(version_cmp("hello", "hello"), Ordering::Equal);
+
+        assert_eq!(version_cmp("file12", "file12"), Ordering::Equal);
+
+        assert_eq!(
+            version_cmp("file12-suffix", "file12-suffix"),
+            Ordering::Equal
+        );
+
+        assert_eq!(
+            version_cmp("file12-suffix24", "file12-suffix24"),
+            Ordering::Equal
+        );
+
+        // Shortened names
+        assert_eq!(version_cmp("world", "wo"), Ordering::Greater,);
+
+        assert_eq!(version_cmp("hello10wo", "hello10world"), Ordering::Less,);
+
+        // Simple names
+        assert_eq!(version_cmp("world", "hello"), Ordering::Greater,);
+
+        assert_eq!(version_cmp("hello", "world"), Ordering::Less);
+
+        assert_eq!(version_cmp("apple", "ant"), Ordering::Greater);
+
+        assert_eq!(version_cmp("ant", "apple"), Ordering::Less);
+
+        // Uppercase letters
+        assert_eq!(
+            version_cmp("Beef", "apple"),
+            Ordering::Less,
+            "Uppercase letters are sorted before all lowercase letters"
+        );
+
+        assert_eq!(version_cmp("Apple", "apple"), Ordering::Less);
+
+        assert_eq!(version_cmp("apple", "aPple"), Ordering::Greater);
+
+        // Numbers
+        assert_eq!(
+            version_cmp("100", "20"),
+            Ordering::Greater,
+            "Greater numbers are greater even if they start with a smaller digit",
+        );
+
+        assert_eq!(
+            version_cmp("20", "20"),
+            Ordering::Equal,
+            "Equal numbers are equal"
+        );
+
+        assert_eq!(
+            version_cmp("15", "200"),
+            Ordering::Less,
+            "Small numbers are smaller"
+        );
+
+        // Comparing numbers with other characters
+        assert_eq!(
+            version_cmp("1000", "apple"),
+            Ordering::Less,
+            "Numbers are sorted before other characters"
+        );
+
+        assert_eq!(
+            // spell-checker:disable-next-line
+            version_cmp("file1000", "fileapple"),
+            Ordering::Less,
+            "Numbers in the middle of the name are sorted before other characters"
+        );
+
+        // Leading zeroes
+        assert_eq!(
+            version_cmp("012", "12"),
+            Ordering::Less,
+            "A single leading zero can make a difference"
+        );
+
+        assert_eq!(
+            version_cmp("000800", "0000800"),
+            Ordering::Greater,
+            "Leading number of zeroes is used even if both non-zero number of zeros"
+        );
+
+        // Numbers and other characters combined
+        assert_eq!(version_cmp("ab10", "aa11"), Ordering::Greater);
+
+        assert_eq!(
+            version_cmp("aa10", "aa11"),
+            Ordering::Less,
+            "Numbers after other characters are handled correctly."
+        );
+
+        assert_eq!(
+            version_cmp("aa2", "aa100"),
+            Ordering::Less,
+            "Numbers after alphabetical characters are handled correctly."
+        );
+
+        assert_eq!(
+            version_cmp("aa10bb", "aa11aa"),
+            Ordering::Less,
+            "Number is used even if alphabetical characters after it differ."
+        );
+
+        assert_eq!(
+            version_cmp("aa10aa0010", "aa11aa1"),
+            Ordering::Less,
+            "Second number is ignored if the first number differs."
+        );
+
+        assert_eq!(
+            version_cmp("aa10aa0010", "aa10aa1"),
+            Ordering::Greater,
+            "Second number is used if the rest is equal."
+        );
+
+        assert_eq!(
+            version_cmp("aa10aa0010", "aa00010aa1"),
+            Ordering::Greater,
+            "Second number is used if the rest is equal up to leading zeroes of the first number."
+        );
+
+        assert_eq!(
+            version_cmp("aa10aa0022", "aa010aa022"),
+            Ordering::Greater,
+            "The leading zeroes of the first number has priority."
+        );
+
+        assert_eq!(
+            version_cmp("aa10aa0022", "aa10aa022"),
+            Ordering::Less,
+            "The leading zeroes of other numbers than the first are used."
+        );
+
+        assert_eq!(
+            version_cmp("file-1.4", "file-1.13"),
+            Ordering::Less,
+            "Periods are handled as normal text, not as a decimal point."
+        );
+
+        // Greater than u64::Max
+        // u64 == 18446744073709551615 so this should be plenty:
+        //        20000000000000000000000
+        assert_eq!(
+            version_cmp("aa2000000000000000000000bb", "aa002000000000000000000001bb"),
+            Ordering::Less,
+            "Numbers larger than u64::MAX are handled correctly without crashing"
+        );
+
+        assert_eq!(
+            version_cmp("aa2000000000000000000000bb", "aa002000000000000000000000bb"),
+            Ordering::Greater,
+            "Leading zeroes for numbers larger than u64::MAX are \
+            handled correctly without crashing"
+        );
+
+        assert_eq!(
+            version_cmp("  a", "a"),
+            Ordering::Greater,
+            "Whitespace is after letters because letters are before non-letters"
+        );
+
+        assert_eq!(
+            version_cmp("a~", "ab"),
+            Ordering::Less,
+            "A tilde is before other letters"
+        );
+
+        assert_eq!(
+            version_cmp("a~", "a"),
+            Ordering::Less,
+            "A tilde is before the line end"
+        );
+        assert_eq!(
+            version_cmp("~", ""),
+            Ordering::Greater,
+            "A tilde is after the empty string"
+        );
+        assert_eq!(
+            version_cmp(".f", ".1"),
+            Ordering::Greater,
+            "if both start with a dot it is ignored for the comparison"
+        );
+
+        // The following tests are incompatible with GNU as of 2021/06.
+        // I think that's because of a bug in GNU, reported as https://lists.gnu.org/archive/html/bug-coreutils/2021-06/msg00045.html
+        assert_eq!(
+            version_cmp("a..a", "a.+"),
+            Ordering::Less,
+            ".a is stripped before the comparison"
+        );
+        assert_eq!(
+            version_cmp("a.", "a+"),
+            Ordering::Greater,
+            ". is not stripped before the comparison"
+        );
+        assert_eq!(
+            version_cmp("a\0a", "a"),
+            Ordering::Greater,
+            "NULL bytes are handled comparison"
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/parser.rs.html b/src/uucore/parser.rs.html new file mode 100644 index 000000000..f7320d7bd --- /dev/null +++ b/src/uucore/parser.rs.html @@ -0,0 +1,9 @@ +parser.rs - source + +
1
+2
+
+pub mod parse_size;
+pub mod parse_time;
+
+
\ No newline at end of file diff --git a/src/uucore/parser/parse_size.rs.html b/src/uucore/parser/parse_size.rs.html new file mode 100644 index 000000000..06e0e1ca4 --- /dev/null +++ b/src/uucore/parser/parse_size.rs.html @@ -0,0 +1,653 @@ +parse_size.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+
+//  * This file is part of the uutils coreutils package.
+//  *
+//  * For the full copyright and license information, please view the LICENSE
+//  * file that was distributed with this source code.
+
+// spell-checker:ignore (ToDO) hdsf ghead gtail
+
+use std::convert::TryFrom;
+use std::error::Error;
+use std::fmt;
+
+/// Parse a size string into a number of bytes.
+///
+/// A size string comprises an integer and an optional unit. The unit
+/// may be K, M, G, T, P, E, Z or Y (powers of 1024), or KB, MB,
+/// etc. (powers of 1000), or b which is 512.
+/// Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
+///
+/// # Errors
+///
+/// Will return `ParseSizeError` if it's not possible to parse this
+/// string into a number, e.g. if the string does not begin with a
+/// numeral, or if the unit is not one of the supported units described
+/// in the preceding section.
+///
+/// # Examples
+///
+/// ```rust
+/// use uucore::parse_size::parse_size;
+/// assert_eq!(Ok(123), parse_size("123"));
+/// assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
+/// assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
+/// ```
+pub fn parse_size(size: &str) -> Result<usize, ParseSizeError> {
+    if size.is_empty() {
+        return Err(ParseSizeError::parse_failure(size));
+    }
+    // Get the numeric part of the size argument. For example, if the
+    // argument is "123K", then the numeric part is "123".
+    let numeric_string: String = size.chars().take_while(|c| c.is_digit(10)).collect();
+    let number: usize = if !numeric_string.is_empty() {
+        match numeric_string.parse() {
+            Ok(n) => n,
+            Err(_) => return Err(ParseSizeError::parse_failure(size)),
+        }
+    } else {
+        1
+    };
+
+    // Get the alphabetic units part of the size argument and compute
+    // the factor it represents. For example, if the argument is "123K",
+    // then the unit part is "K" and the factor is 1024. This may be the
+    // empty string, in which case, the factor is 1.
+    let unit = &size[numeric_string.len()..];
+    let (base, exponent): (u128, u32) = match unit {
+        "" => (1, 0),
+        "b" => (512, 1), // (`od`, `head` and `tail` use "b")
+        "KiB" | "kiB" | "K" | "k" => (1024, 1),
+        "MiB" | "miB" | "M" | "m" => (1024, 2),
+        "GiB" | "giB" | "G" | "g" => (1024, 3),
+        "TiB" | "tiB" | "T" | "t" => (1024, 4),
+        "PiB" | "piB" | "P" | "p" => (1024, 5),
+        "EiB" | "eiB" | "E" | "e" => (1024, 6),
+        "ZiB" | "ziB" | "Z" | "z" => (1024, 7),
+        "YiB" | "yiB" | "Y" | "y" => (1024, 8),
+        "KB" | "kB" => (1000, 1),
+        "MB" | "mB" => (1000, 2),
+        "GB" | "gB" => (1000, 3),
+        "TB" | "tB" => (1000, 4),
+        "PB" | "pB" => (1000, 5),
+        "EB" | "eB" => (1000, 6),
+        "ZB" | "zB" => (1000, 7),
+        "YB" | "yB" => (1000, 8),
+        _ => return Err(ParseSizeError::parse_failure(size)),
+    };
+    let factor = match usize::try_from(base.pow(exponent)) {
+        Ok(n) => n,
+        Err(_) => return Err(ParseSizeError::size_too_big(size)),
+    };
+    number
+        .checked_mul(factor)
+        .ok_or_else(|| ParseSizeError::size_too_big(size))
+}
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum ParseSizeError {
+    ParseFailure(String), // Syntax
+    SizeTooBig(String),   // Overflow
+}
+
+impl Error for ParseSizeError {
+    fn description(&self) -> &str {
+        match *self {
+            ParseSizeError::ParseFailure(ref s) => &*s,
+            ParseSizeError::SizeTooBig(ref s) => &*s,
+        }
+    }
+}
+
+impl fmt::Display for ParseSizeError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        let s = match self {
+            ParseSizeError::ParseFailure(s) => s,
+            ParseSizeError::SizeTooBig(s) => s,
+        };
+        write!(f, "{}", s)
+    }
+}
+
+impl ParseSizeError {
+    fn parse_failure(s: &str) -> ParseSizeError {
+        // stderr on linux (GNU coreutils 8.32) (LC_ALL=C)
+        // has to be handled in the respective uutils because strings differ, e.g.:
+        //
+        // `NUM`
+        // head:     invalid number of bytes: '1fb'
+        // tail:     invalid number of bytes: '1fb'
+        //
+        // `SIZE`
+        // split:    invalid number of bytes: '1fb'
+        // truncate: Invalid number: '1fb'
+        //
+        // `MODE`
+        // stdbuf:   invalid mode '1fb'
+        //
+        // `SIZE`
+        // sort:     invalid suffix in --buffer-size argument '1fb'
+        // sort:     invalid --buffer-size argument 'fb'
+        //
+        // `SIZE`
+        // du:       invalid suffix in --buffer-size argument '1fb'
+        // du:       invalid suffix in --threshold argument '1fb'
+        // du:       invalid --buffer-size argument 'fb'
+        // du:       invalid --threshold argument 'fb'
+        //
+        // `BYTES`
+        // od:       invalid suffix in --read-bytes argument '1fb'
+        // od:       invalid --read-bytes argument  argument 'fb'
+        //                   --skip-bytes
+        //                   --width
+        //                   --strings
+        // etc.
+        ParseSizeError::ParseFailure(format!("'{}'", s))
+    }
+
+    fn size_too_big(s: &str) -> ParseSizeError {
+        // stderr on linux (GNU coreutils 8.32) (LC_ALL=C)
+        // has to be handled in the respective uutils because strings differ, e.g.:
+        //
+        // head:     invalid number of bytes: '1Y': Value too large for defined data type
+        // tail:     invalid number of bytes: '1Y': Value too large for defined data type
+        // split:    invalid number of bytes: '1Y': Value too large for defined data type
+        // truncate:          Invalid number: '1Y': Value too large for defined data type
+        // stdbuf:               invalid mode '1Y': Value too large for defined data type
+        // sort:     -S argument '1Y' too large
+        // du:       -B argument '1Y' too large
+        // od:       -N argument '1Y' too large
+        // etc.
+        //
+        // stderr on macos (brew - GNU coreutils 8.32) also differs for the same version, e.g.:
+        // ghead:   invalid number of bytes: '1Y': Value too large to be stored in data type
+        // gtail:   invalid number of bytes: '1Y': Value too large to be stored in data type
+        ParseSizeError::SizeTooBig(format!("'{}': Value too large for defined data type", s))
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn variant_eq(a: &ParseSizeError, b: &ParseSizeError) -> bool {
+        std::mem::discriminant(a) == std::mem::discriminant(b)
+    }
+
+    #[test]
+    fn all_suffixes() {
+        // Units  are  K,M,G,T,P,E,Z,Y  (powers  of 1024) or KB,MB,... (powers of 1000).
+        // Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
+        let suffixes = [
+            ('K', 1u32),
+            ('M', 2u32),
+            ('G', 3u32),
+            ('T', 4u32),
+            ('P', 5u32),
+            ('E', 6u32),
+            #[cfg(target_pointer_width = "128")]
+            ('Z', 7u32), // ParseSizeError::SizeTooBig on x64
+            #[cfg(target_pointer_width = "128")]
+            ('Y', 8u32), // ParseSizeError::SizeTooBig on x64
+        ];
+
+        for &(c, exp) in &suffixes {
+            let s = format!("2{}B", c); // KB
+            assert_eq!(Ok((2 * (1000_u128).pow(exp)) as usize), parse_size(&s));
+            let s = format!("2{}", c); // K
+            assert_eq!(Ok((2 * (1024_u128).pow(exp)) as usize), parse_size(&s));
+            let s = format!("2{}iB", c); // KiB
+            assert_eq!(Ok((2 * (1024_u128).pow(exp)) as usize), parse_size(&s));
+            let s = format!("2{}iB", c.to_lowercase()); // kiB
+            assert_eq!(Ok((2 * (1024_u128).pow(exp)) as usize), parse_size(&s));
+
+            // suffix only
+            let s = format!("{}B", c); // KB
+            assert_eq!(Ok(((1000_u128).pow(exp)) as usize), parse_size(&s));
+            let s = format!("{}", c); // K
+            assert_eq!(Ok(((1024_u128).pow(exp)) as usize), parse_size(&s));
+            let s = format!("{}iB", c); // KiB
+            assert_eq!(Ok(((1024_u128).pow(exp)) as usize), parse_size(&s));
+            let s = format!("{}iB", c.to_lowercase()); // kiB
+            assert_eq!(Ok(((1024_u128).pow(exp)) as usize), parse_size(&s));
+        }
+    }
+
+    #[test]
+    #[cfg(not(target_pointer_width = "128"))]
+    fn overflow_x64() {
+        assert!(parse_size("10000000000000000000000").is_err());
+        assert!(parse_size("1000000000T").is_err());
+        assert!(parse_size("100000P").is_err());
+        assert!(parse_size("100E").is_err());
+        assert!(parse_size("1Z").is_err());
+        assert!(parse_size("1Y").is_err());
+
+        assert!(variant_eq(
+            &parse_size("1Z").unwrap_err(),
+            &ParseSizeError::SizeTooBig(String::new())
+        ));
+
+        assert_eq!(
+            ParseSizeError::SizeTooBig("'1Y': Value too large for defined data type".to_string()),
+            parse_size("1Y").unwrap_err()
+        );
+    }
+
+    #[test]
+    #[cfg(target_pointer_width = "32")]
+    fn overflow_x32() {
+        assert!(variant_eq(
+            &parse_size("1T").unwrap_err(),
+            &ParseSizeError::SizeTooBig(String::new())
+        ));
+        assert!(variant_eq(
+            &parse_size("1000G").unwrap_err(),
+            &ParseSizeError::SizeTooBig(String::new())
+        ));
+    }
+
+    #[test]
+    fn invalid_syntax() {
+        let test_strings = [
+            "328hdsf3290",
+            "5MiB nonsense",
+            "5mib",
+            "biB",
+            "-",
+            "+",
+            "",
+            "-1",
+            "1e2",
+            "∞",
+        ];
+        for &test_string in &test_strings {
+            assert_eq!(
+                parse_size(test_string).unwrap_err(),
+                ParseSizeError::ParseFailure(format!("'{}'", test_string))
+            );
+        }
+    }
+
+    #[test]
+    fn b_suffix() {
+        assert_eq!(Ok(3 * 512), parse_size("3b")); // b is 512
+    }
+
+    #[test]
+    fn no_suffix() {
+        assert_eq!(Ok(1234), parse_size("1234"));
+        assert_eq!(Ok(0), parse_size("0"));
+        assert_eq!(Ok(5), parse_size("5"));
+        assert_eq!(Ok(999), parse_size("999"));
+    }
+
+    #[test]
+    fn kilobytes_suffix() {
+        assert_eq!(Ok(123 * 1000), parse_size("123KB")); // KB is 1000
+        assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
+        assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
+        assert_eq!(Ok(0), parse_size("0K"));
+        assert_eq!(Ok(0), parse_size("0KB"));
+        assert_eq!(Ok(1000), parse_size("KB"));
+        assert_eq!(Ok(1024), parse_size("K"));
+        assert_eq!(Ok(2000), parse_size("2kB"));
+        assert_eq!(Ok(4000), parse_size("4KB"));
+    }
+
+    #[test]
+    fn megabytes_suffix() {
+        assert_eq!(Ok(123 * 1024 * 1024), parse_size("123M"));
+        assert_eq!(Ok(123 * 1000 * 1000), parse_size("123MB"));
+        assert_eq!(Ok(1024 * 1024), parse_size("M"));
+        assert_eq!(Ok(1000 * 1000), parse_size("MB"));
+        assert_eq!(Ok(2 * 1_048_576), parse_size("2m"));
+        assert_eq!(Ok(4 * 1_048_576), parse_size("4M"));
+        assert_eq!(Ok(2_000_000), parse_size("2mB"));
+        assert_eq!(Ok(4_000_000), parse_size("4MB"));
+    }
+
+    #[test]
+    fn gigabytes_suffix() {
+        assert_eq!(Ok(1_073_741_824), parse_size("1G"));
+        assert_eq!(Ok(2_000_000_000), parse_size("2GB"));
+    }
+
+    #[test]
+    #[cfg(target_pointer_width = "64")]
+    fn x64() {
+        assert_eq!(Ok(1_099_511_627_776), parse_size("1T"));
+        assert_eq!(Ok(1_125_899_906_842_624), parse_size("1P"));
+        assert_eq!(Ok(1_152_921_504_606_846_976), parse_size("1E"));
+        assert_eq!(Ok(2_000_000_000_000), parse_size("2TB"));
+        assert_eq!(Ok(2_000_000_000_000_000), parse_size("2PB"));
+        assert_eq!(Ok(2_000_000_000_000_000_000), parse_size("2EB"));
+    }
+}
+
+
\ No newline at end of file diff --git a/src/uucore/parser/parse_time.rs.html b/src/uucore/parser/parse_time.rs.html new file mode 100644 index 000000000..b80524f41 --- /dev/null +++ b/src/uucore/parser/parse_time.rs.html @@ -0,0 +1,87 @@ +parse_time.rs - source + +
 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+
+// This file is part of the uutils coreutils package.
+//
+// (c) Alex Lyon <arcterus@mail.com>
+//
+// For the full copyright and license information, please view the LICENSE
+// file that was distributed with this source code.
+
+// spell-checker:ignore (vars) NANOS numstr
+
+use std::time::Duration;
+
+pub fn from_str(string: &str) -> Result<Duration, String> {
+    let len = string.len();
+    if len == 0 {
+        return Err("empty string".to_owned());
+    }
+    let slice = &string[..len - 1];
+    let (numstr, times) = match string.chars().next_back().unwrap() {
+        's' | 'S' => (slice, 1),
+        'm' | 'M' => (slice, 60),
+        'h' | 'H' => (slice, 60 * 60),
+        'd' | 'D' => (slice, 60 * 60 * 24),
+        val if !val.is_alphabetic() => (string, 1),
+        _ => {
+            if string == "inf" || string == "infinity" {
+                ("inf", 1)
+            } else {
+                return Err(format!("invalid time interval '{}'", string));
+            }
+        }
+    };
+    let num = numstr
+        .parse::<f64>()
+        .map_err(|e| format!("invalid time interval '{}': {}", string, e))?;
+
+    const NANOS_PER_SEC: u32 = 1_000_000_000;
+    let whole_secs = num.trunc();
+    let nanos = (num.fract() * (NANOS_PER_SEC as f64)).trunc();
+    let duration = Duration::new(whole_secs as u64, nanos as u32);
+    Ok(duration * times)
+}
+
+
\ No newline at end of file diff --git a/src/uucore_procs/lib.rs.html b/src/uucore_procs/lib.rs.html new file mode 100644 index 000000000..a44d75c19 --- /dev/null +++ b/src/uucore_procs/lib.rs.html @@ -0,0 +1,237 @@ +lib.rs - source + +
  1
+  2
+  3
+  4
+  5
+  6
+  7
+  8
+  9
+ 10
+ 11
+ 12
+ 13
+ 14
+ 15
+ 16
+ 17
+ 18
+ 19
+ 20
+ 21
+ 22
+ 23
+ 24
+ 25
+ 26
+ 27
+ 28
+ 29
+ 30
+ 31
+ 32
+ 33
+ 34
+ 35
+ 36
+ 37
+ 38
+ 39
+ 40
+ 41
+ 42
+ 43
+ 44
+ 45
+ 46
+ 47
+ 48
+ 49
+ 50
+ 51
+ 52
+ 53
+ 54
+ 55
+ 56
+ 57
+ 58
+ 59
+ 60
+ 61
+ 62
+ 63
+ 64
+ 65
+ 66
+ 67
+ 68
+ 69
+ 70
+ 71
+ 72
+ 73
+ 74
+ 75
+ 76
+ 77
+ 78
+ 79
+ 80
+ 81
+ 82
+ 83
+ 84
+ 85
+ 86
+ 87
+ 88
+ 89
+ 90
+ 91
+ 92
+ 93
+ 94
+ 95
+ 96
+ 97
+ 98
+ 99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+
+// Copyright (C) ~ Roy Ivy III <rivy.dev@gmail.com>; MIT license
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+use proc_macro2::{Ident, Span};
+use quote::quote;
+use syn::{self, parse_macro_input, ItemFn};
+
+//## rust proc-macro background info
+//* ref: <https://dev.to/naufraghi/procedural-macro-in-rust-101-k3f> @@ <http://archive.is/Vbr5e>
+//* ref: [path construction from LitStr](https://oschwald.github.io/maxminddb-rust/syn/struct.LitStr.html) @@ <http://archive.is/8YDua>
+
+//## proc_dbg macro
+//* used to help debug the compile-time proc_macro code
+
+#[cfg(feature = "debug")]
+macro_rules! proc_dbg {
+    ($x:expr) => {
+        dbg!($x)
+    };
+}
+#[cfg(not(feature = "debug"))]
+macro_rules! proc_dbg {
+    ($x:expr) => {};
+}
+
+//## main!()
+
+// main!( EXPR )
+// generates a `main()` function for utilities within the uutils group
+// EXPR == syn::Expr::Lit::String | syn::Expr::Path::Ident ~ EXPR contains the lexical path to the utility `uumain()` function
+//* NOTE: EXPR is ultimately expected to be a multi-segment lexical path (eg, `crate::func`); so, if a single segment path is provided, a trailing "::uumain" is automatically added
+//* for more generic use (and future use of "eager" macros), EXPR may be in either STRING or IDENT form
+
+struct Tokens {
+    expr: syn::Expr,
+}
+
+impl syn::parse::Parse for Tokens {
+    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+        Ok(Tokens {
+            expr: input.parse()?,
+        })
+    }
+}
+
+#[proc_macro]
+pub fn main(stream: TokenStream) -> TokenStream {
+    let Tokens { expr } = syn::parse_macro_input!(stream as Tokens);
+    proc_dbg!(&expr);
+
+    const ARG_PANIC_TEXT: &str =
+        "expected ident lexical path (or a literal string version) to 'uumain()' as argument";
+
+    // match EXPR as a string literal or an ident path, o/w panic!()
+    let mut expr = match expr {
+        syn::Expr::Lit(expr_lit) => match expr_lit.lit {
+            syn::Lit::Str(ref lit_str) => lit_str.parse::<syn::ExprPath>().unwrap(),
+            _ => panic!("{}", ARG_PANIC_TEXT),
+        },
+        syn::Expr::Path(expr_path) => expr_path,
+        _ => panic!("{}", ARG_PANIC_TEXT),
+    };
+    proc_dbg!(&expr);
+
+    // for a single segment ExprPath argument, add trailing '::uumain' segment
+    if expr.path.segments.len() < 2 {
+        expr = syn::parse_quote!( #expr::uumain );
+    };
+    proc_dbg!(&expr);
+
+    let f = quote::quote! { #expr(uucore::args_os()) };
+    proc_dbg!(&f);
+
+    // generate a uutils utility `main()` function, tailored for the calling utility
+    let result = quote::quote! {
+        fn main() {
+            use std::io::Write;
+            uucore::panic::mute_sigpipe_panic(); // suppress extraneous error output for SIGPIPE failures/panics
+            let code = #f; // execute utility code
+            std::io::stdout().flush().expect("could not flush stdout"); // (defensively) flush stdout for utility prior to exit; see <https://github.com/rust-lang/rust/issues/23818>
+            std::process::exit(code);
+        }
+    };
+    TokenStream::from(result)
+}
+
+#[proc_macro_attribute]
+pub fn gen_uumain(_args: TokenStream, stream: TokenStream) -> TokenStream {
+    let mut ast = parse_macro_input!(stream as ItemFn);
+
+    // Change the name of the function to "uumain_result" to prevent name-conflicts
+    ast.sig.ident = Ident::new("uumain_result", Span::call_site());
+
+    let new = quote!(
+        pub fn uumain(args: impl uucore::Args) -> i32 {
+            #ast
+            let result = uumain_result(args);
+            match result {
+                Ok(()) => uucore::error::get_exit_code(),
+                Err(e) => {
+                    let s = format!("{}", e);
+                    if s != "" {
+                        show_error!("{}", s);
+                    }
+                    if e.usage() {
+                        eprintln!("Try '{} --help' for more information.", uucore::execution_phrase());
+                    }
+                    e.code()
+                }
+            }
+        }
+    );
+
+    TokenStream::from(new)
+}
+
+
\ No newline at end of file diff --git a/src/wc/main.rs.html b/src/wc/main.rs.html new file mode 100644 index 000000000..8c07c162e --- /dev/null +++ b/src/wc/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_wc);
+
+
\ No newline at end of file diff --git a/src/who/main.rs.html b/src/who/main.rs.html new file mode 100644 index 000000000..43effa7ae --- /dev/null +++ b/src/who/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_who);
+
+
\ No newline at end of file diff --git a/src/whoami/main.rs.html b/src/whoami/main.rs.html new file mode 100644 index 000000000..a375119a9 --- /dev/null +++ b/src/whoami/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_whoami);
+
+
\ No newline at end of file diff --git a/src/yes/main.rs.html b/src/yes/main.rs.html new file mode 100644 index 000000000..60564eae0 --- /dev/null +++ b/src/yes/main.rs.html @@ -0,0 +1,7 @@ +main.rs - source + +
1
+
+uucore_procs::main!(uu_yes);
+
+
\ No newline at end of file diff --git a/stat/all.html b/stat/all.html new file mode 100644 index 000000000..8b809e6c2 --- /dev/null +++ b/stat/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/stat/fn.main.html b/stat/fn.main.html new file mode 100644 index 000000000..c507a6619 --- /dev/null +++ b/stat/fn.main.html @@ -0,0 +1,3 @@ +main in stat - Rust + +

Function stat::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/stat/index.html b/stat/index.html new file mode 100644 index 000000000..ff38401b9 --- /dev/null +++ b/stat/index.html @@ -0,0 +1,4 @@ +stat - Rust + +

Crate stat[][src]

Functions

+
main
\ No newline at end of file diff --git a/stat/sidebar-items.js b/stat/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/stat/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/stdbuf/all.html b/stdbuf/all.html new file mode 100644 index 000000000..48fb25bcd --- /dev/null +++ b/stdbuf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/stdbuf/fn.main.html b/stdbuf/fn.main.html new file mode 100644 index 000000000..b66610039 --- /dev/null +++ b/stdbuf/fn.main.html @@ -0,0 +1,3 @@ +main in stdbuf - Rust + +

Function stdbuf::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/stdbuf/index.html b/stdbuf/index.html new file mode 100644 index 000000000..3e8aa771e --- /dev/null +++ b/stdbuf/index.html @@ -0,0 +1,4 @@ +stdbuf - Rust + +

Crate stdbuf[][src]

Functions

+
main
\ No newline at end of file diff --git a/stdbuf/sidebar-items.js b/stdbuf/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/stdbuf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/storage.js b/storage.js new file mode 100644 index 000000000..6b16cbd83 --- /dev/null +++ b/storage.js @@ -0,0 +1 @@ +var resourcesSuffix="";var darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");window.mainTheme=document.getElementById("mainThemeStyle");var settingsDataset=(function(){var settingsElement=document.getElementById("default-settings");if(settingsElement===null){return null}var dataset=settingsElement.dataset;if(dataset===undefined){return null}return dataset})();function getSettingValue(settingName){var current=getCurrentValue('rustdoc-'+settingName);if(current!==null){return current}if(settingsDataset!==null){var def=settingsDataset[settingName.replace(/-/g,'_')];if(def!==undefined){return def}}return null}var localStoredTheme=getSettingValue("theme");var savedHref=[];function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(!elem||!elem.classList){return}elem.classList.add(className)}function removeClass(elem,className){if(!elem||!elem.classList){return}elem.classList.remove(className)}function onEach(arr,func,reversed){if(arr&&arr.length>0&&func){var length=arr.length;var i;if(reversed){for(i=length-1;i>=0;--i){if(func(arr[i])){return true}}}else{for(i=0;i=0){updateLocalStorage("rustdoc-preferred-dark-theme",localStoredTheme)}updateSystemTheme()}else{switchTheme(window.currentTheme,window.mainTheme,getSettingValue("theme")||"light",false)} \ No newline at end of file diff --git a/sum/all.html b/sum/all.html new file mode 100644 index 000000000..a5821bf57 --- /dev/null +++ b/sum/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/sum/fn.main.html b/sum/fn.main.html new file mode 100644 index 000000000..547a9a366 --- /dev/null +++ b/sum/fn.main.html @@ -0,0 +1,3 @@ +main in sum - Rust + +

Function sum::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/sum/index.html b/sum/index.html new file mode 100644 index 000000000..fff0793e8 --- /dev/null +++ b/sum/index.html @@ -0,0 +1,4 @@ +sum - Rust + +

Crate sum[][src]

Functions

+
main
\ No newline at end of file diff --git a/sum/sidebar-items.js b/sum/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/sum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/sync/all.html b/sync/all.html new file mode 100644 index 000000000..7226eefa4 --- /dev/null +++ b/sync/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/sync/fn.main.html b/sync/fn.main.html new file mode 100644 index 000000000..dc4d02b6b --- /dev/null +++ b/sync/fn.main.html @@ -0,0 +1,3 @@ +main in sync - Rust + +

Function sync::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/sync/index.html b/sync/index.html new file mode 100644 index 000000000..5097c4fcc --- /dev/null +++ b/sync/index.html @@ -0,0 +1,4 @@ +sync - Rust + +

Crate sync[][src]

Functions

+
main
\ No newline at end of file diff --git a/sync/sidebar-items.js b/sync/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/sync/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/tac/all.html b/tac/all.html new file mode 100644 index 000000000..a6cb228c6 --- /dev/null +++ b/tac/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/tac/fn.main.html b/tac/fn.main.html new file mode 100644 index 000000000..71c0303f1 --- /dev/null +++ b/tac/fn.main.html @@ -0,0 +1,3 @@ +main in tac - Rust + +

Function tac::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/tac/index.html b/tac/index.html new file mode 100644 index 000000000..8a58feb10 --- /dev/null +++ b/tac/index.html @@ -0,0 +1,4 @@ +tac - Rust + +

Crate tac[][src]

Functions

+
main
\ No newline at end of file diff --git a/tac/sidebar-items.js b/tac/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/tac/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/tail/all.html b/tail/all.html new file mode 100644 index 000000000..bf4d07276 --- /dev/null +++ b/tail/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/tail/fn.main.html b/tail/fn.main.html new file mode 100644 index 000000000..fce7aed92 --- /dev/null +++ b/tail/fn.main.html @@ -0,0 +1,3 @@ +main in tail - Rust + +

Function tail::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/tail/index.html b/tail/index.html new file mode 100644 index 000000000..11f105157 --- /dev/null +++ b/tail/index.html @@ -0,0 +1,4 @@ +tail - Rust + +

Crate tail[][src]

Functions

+
main
\ No newline at end of file diff --git a/tail/sidebar-items.js b/tail/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/tail/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/tee/all.html b/tee/all.html new file mode 100644 index 000000000..166067012 --- /dev/null +++ b/tee/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/tee/fn.main.html b/tee/fn.main.html new file mode 100644 index 000000000..212b5e044 --- /dev/null +++ b/tee/fn.main.html @@ -0,0 +1,3 @@ +main in tee - Rust + +

Function tee::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/tee/index.html b/tee/index.html new file mode 100644 index 000000000..a2d4fa8c1 --- /dev/null +++ b/tee/index.html @@ -0,0 +1,4 @@ +tee - Rust + +

Crate tee[][src]

Functions

+
main
\ No newline at end of file diff --git a/tee/sidebar-items.js b/tee/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/tee/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/test/all.html b/test/all.html new file mode 100644 index 000000000..7e095d8d5 --- /dev/null +++ b/test/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/test/fn.main.html b/test/fn.main.html new file mode 100644 index 000000000..3515e5e47 --- /dev/null +++ b/test/fn.main.html @@ -0,0 +1,3 @@ +main in test - Rust + +

Function test::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/test/index.html b/test/index.html new file mode 100644 index 000000000..b523222e8 --- /dev/null +++ b/test/index.html @@ -0,0 +1,4 @@ +test - Rust + +

Crate test[][src]

Functions

+
main
\ No newline at end of file diff --git a/test/sidebar-items.js b/test/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/test/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/timeout/all.html b/timeout/all.html new file mode 100644 index 000000000..4460d132c --- /dev/null +++ b/timeout/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/timeout/fn.main.html b/timeout/fn.main.html new file mode 100644 index 000000000..303a4d2f0 --- /dev/null +++ b/timeout/fn.main.html @@ -0,0 +1,3 @@ +main in timeout - Rust + +

Function timeout::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/timeout/index.html b/timeout/index.html new file mode 100644 index 000000000..b149eef89 --- /dev/null +++ b/timeout/index.html @@ -0,0 +1,4 @@ +timeout - Rust + +

Crate timeout[][src]

Functions

+
main
\ No newline at end of file diff --git a/timeout/sidebar-items.js b/timeout/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/timeout/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/touch/all.html b/touch/all.html new file mode 100644 index 000000000..62a52c035 --- /dev/null +++ b/touch/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/touch/fn.main.html b/touch/fn.main.html new file mode 100644 index 000000000..04c8a4de3 --- /dev/null +++ b/touch/fn.main.html @@ -0,0 +1,3 @@ +main in touch - Rust + +

Function touch::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/touch/index.html b/touch/index.html new file mode 100644 index 000000000..e9ec34170 --- /dev/null +++ b/touch/index.html @@ -0,0 +1,4 @@ +touch - Rust + +

Crate touch[][src]

Functions

+
main
\ No newline at end of file diff --git a/touch/sidebar-items.js b/touch/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/touch/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/tr/all.html b/tr/all.html new file mode 100644 index 000000000..a90642118 --- /dev/null +++ b/tr/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/tr/fn.main.html b/tr/fn.main.html new file mode 100644 index 000000000..41791ed68 --- /dev/null +++ b/tr/fn.main.html @@ -0,0 +1,3 @@ +main in tr - Rust + +

Function tr::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/tr/index.html b/tr/index.html new file mode 100644 index 000000000..38f300f93 --- /dev/null +++ b/tr/index.html @@ -0,0 +1,4 @@ +tr - Rust + +

Crate tr[][src]

Functions

+
main
\ No newline at end of file diff --git a/tr/sidebar-items.js b/tr/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/tr/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/true/all.html b/true/all.html new file mode 100644 index 000000000..273196726 --- /dev/null +++ b/true/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/true/fn.main.html b/true/fn.main.html new file mode 100644 index 000000000..97fe4413f --- /dev/null +++ b/true/fn.main.html @@ -0,0 +1,3 @@ +main in true - Rust + +

Function true::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/true/index.html b/true/index.html new file mode 100644 index 000000000..f7fcf2b6d --- /dev/null +++ b/true/index.html @@ -0,0 +1,4 @@ +true - Rust + +

Crate true[][src]

Functions

+
main
\ No newline at end of file diff --git a/true/sidebar-items.js b/true/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/true/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/truncate/all.html b/truncate/all.html new file mode 100644 index 000000000..3d4bd773e --- /dev/null +++ b/truncate/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/truncate/fn.main.html b/truncate/fn.main.html new file mode 100644 index 000000000..89e6ed2f3 --- /dev/null +++ b/truncate/fn.main.html @@ -0,0 +1,3 @@ +main in truncate - Rust + +

Function truncate::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/truncate/index.html b/truncate/index.html new file mode 100644 index 000000000..fa16eab5b --- /dev/null +++ b/truncate/index.html @@ -0,0 +1,4 @@ +truncate - Rust + +

Crate truncate[][src]

Functions

+
main
\ No newline at end of file diff --git a/truncate/sidebar-items.js b/truncate/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/truncate/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/tsort/all.html b/tsort/all.html new file mode 100644 index 000000000..1b8fb35d1 --- /dev/null +++ b/tsort/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/tsort/fn.main.html b/tsort/fn.main.html new file mode 100644 index 000000000..188ac326c --- /dev/null +++ b/tsort/fn.main.html @@ -0,0 +1,3 @@ +main in tsort - Rust + +

Function tsort::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/tsort/index.html b/tsort/index.html new file mode 100644 index 000000000..a5f916651 --- /dev/null +++ b/tsort/index.html @@ -0,0 +1,4 @@ +tsort - Rust + +

Crate tsort[][src]

Functions

+
main
\ No newline at end of file diff --git a/tsort/sidebar-items.js b/tsort/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/tsort/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/tty/all.html b/tty/all.html new file mode 100644 index 000000000..f2e8cce0a --- /dev/null +++ b/tty/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/tty/fn.main.html b/tty/fn.main.html new file mode 100644 index 000000000..28fc413ac --- /dev/null +++ b/tty/fn.main.html @@ -0,0 +1,3 @@ +main in tty - Rust + +

Function tty::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/tty/index.html b/tty/index.html new file mode 100644 index 000000000..0dd8f0bf5 --- /dev/null +++ b/tty/index.html @@ -0,0 +1,4 @@ +tty - Rust + +

Crate tty[][src]

Functions

+
main
\ No newline at end of file diff --git a/tty/sidebar-items.js b/tty/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/tty/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/uname/all.html b/uname/all.html new file mode 100644 index 000000000..e5e314d71 --- /dev/null +++ b/uname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uname/fn.main.html b/uname/fn.main.html new file mode 100644 index 000000000..a2a66d000 --- /dev/null +++ b/uname/fn.main.html @@ -0,0 +1,3 @@ +main in uname - Rust + +

Function uname::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/uname/index.html b/uname/index.html new file mode 100644 index 000000000..c65414aed --- /dev/null +++ b/uname/index.html @@ -0,0 +1,4 @@ +uname - Rust + +

Crate uname[][src]

Functions

+
main
\ No newline at end of file diff --git a/uname/sidebar-items.js b/uname/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/uname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/unexpand/all.html b/unexpand/all.html new file mode 100644 index 000000000..a4655791c --- /dev/null +++ b/unexpand/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/unexpand/fn.main.html b/unexpand/fn.main.html new file mode 100644 index 000000000..5b63ba147 --- /dev/null +++ b/unexpand/fn.main.html @@ -0,0 +1,3 @@ +main in unexpand - Rust + +

Function unexpand::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/unexpand/index.html b/unexpand/index.html new file mode 100644 index 000000000..e5d1bb514 --- /dev/null +++ b/unexpand/index.html @@ -0,0 +1,4 @@ +unexpand - Rust + +

Crate unexpand[][src]

Functions

+
main
\ No newline at end of file diff --git a/unexpand/sidebar-items.js b/unexpand/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/unexpand/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/uniq/all.html b/uniq/all.html new file mode 100644 index 000000000..5a14b06b8 --- /dev/null +++ b/uniq/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uniq/fn.main.html b/uniq/fn.main.html new file mode 100644 index 000000000..29707e201 --- /dev/null +++ b/uniq/fn.main.html @@ -0,0 +1,3 @@ +main in uniq - Rust + +

Function uniq::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/uniq/index.html b/uniq/index.html new file mode 100644 index 000000000..64ba503b4 --- /dev/null +++ b/uniq/index.html @@ -0,0 +1,4 @@ +uniq - Rust + +

Crate uniq[][src]

Functions

+
main
\ No newline at end of file diff --git a/uniq/sidebar-items.js b/uniq/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/uniq/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/unlink/all.html b/unlink/all.html new file mode 100644 index 000000000..971e573cd --- /dev/null +++ b/unlink/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/unlink/fn.main.html b/unlink/fn.main.html new file mode 100644 index 000000000..a31cb6353 --- /dev/null +++ b/unlink/fn.main.html @@ -0,0 +1,3 @@ +main in unlink - Rust + +

Function unlink::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/unlink/index.html b/unlink/index.html new file mode 100644 index 000000000..eb98300a8 --- /dev/null +++ b/unlink/index.html @@ -0,0 +1,4 @@ +unlink - Rust + +

Crate unlink[][src]

Functions

+
main
\ No newline at end of file diff --git a/unlink/sidebar-items.js b/unlink/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/unlink/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/uptime/all.html b/uptime/all.html new file mode 100644 index 000000000..904b21b56 --- /dev/null +++ b/uptime/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uptime/fn.main.html b/uptime/fn.main.html new file mode 100644 index 000000000..fcee0f32f --- /dev/null +++ b/uptime/fn.main.html @@ -0,0 +1,3 @@ +main in uptime - Rust + +

Function uptime::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/uptime/index.html b/uptime/index.html new file mode 100644 index 000000000..7ea5d5c43 --- /dev/null +++ b/uptime/index.html @@ -0,0 +1,4 @@ +uptime - Rust + +

Crate uptime[][src]

Functions

+
main
\ No newline at end of file diff --git a/uptime/sidebar-items.js b/uptime/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/uptime/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/users/all.html b/users/all.html new file mode 100644 index 000000000..e3742c6c0 --- /dev/null +++ b/users/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/users/fn.main.html b/users/fn.main.html new file mode 100644 index 000000000..103a1ae39 --- /dev/null +++ b/users/fn.main.html @@ -0,0 +1,3 @@ +main in users - Rust + +

Function users::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/users/index.html b/users/index.html new file mode 100644 index 000000000..8e2be0272 --- /dev/null +++ b/users/index.html @@ -0,0 +1,4 @@ +users - Rust + +

Crate users[][src]

Functions

+
main
\ No newline at end of file diff --git a/users/sidebar-items.js b/users/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/users/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/uu_arch/all.html b/uu_arch/all.html new file mode 100644 index 000000000..2ac6ba7be --- /dev/null +++ b/uu_arch/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_arch/fn.uu_app.html b/uu_arch/fn.uu_app.html new file mode 100644 index 000000000..85a603efc --- /dev/null +++ b/uu_arch/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_arch - Rust + +

Function uu_arch::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_arch/fn.uumain.html b/uu_arch/fn.uumain.html new file mode 100644 index 000000000..33cd5b40e --- /dev/null +++ b/uu_arch/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_arch - Rust + +

Function uu_arch::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_arch/index.html b/uu_arch/index.html new file mode 100644 index 000000000..0b453ced9 --- /dev/null +++ b/uu_arch/index.html @@ -0,0 +1,4 @@ +uu_arch - Rust + +

Crate uu_arch[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_arch/sidebar-items.js b/uu_arch/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_arch/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_base32/all.html b/uu_base32/all.html new file mode 100644 index 000000000..d0a2b802b --- /dev/null +++ b/uu_base32/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Functions

Statics

\ No newline at end of file diff --git a/uu_base32/base_common/fn.base_app.html b/uu_base32/base_common/fn.base_app.html new file mode 100644 index 000000000..25f8069f2 --- /dev/null +++ b/uu_base32/base_common/fn.base_app.html @@ -0,0 +1,3 @@ +base_app in uu_base32::base_common - Rust + +

Function uu_base32::base_common::base_app[][src]

pub fn base_app<'a>(
    name: &str,
    version: &'a str,
    about: &'a str
) -> App<'static, 'a>
\ No newline at end of file diff --git a/uu_base32/base_common/fn.get_input.html b/uu_base32/base_common/fn.get_input.html new file mode 100644 index 000000000..136bc9087 --- /dev/null +++ b/uu_base32/base_common/fn.get_input.html @@ -0,0 +1,3 @@ +get_input in uu_base32::base_common - Rust + +

Function uu_base32::base_common::get_input[][src]

pub fn get_input<'a>(
    config: &Config,
    stdin_ref: &'a Stdin
) -> Box<dyn Read + 'a>
\ No newline at end of file diff --git a/uu_base32/base_common/fn.handle_input.html b/uu_base32/base_common/fn.handle_input.html new file mode 100644 index 000000000..1ad1f0b06 --- /dev/null +++ b/uu_base32/base_common/fn.handle_input.html @@ -0,0 +1,3 @@ +handle_input in uu_base32::base_common - Rust + +

Function uu_base32::base_common::handle_input[][src]

pub fn handle_input<R: Read>(
    input: &mut R,
    format: Format,
    line_wrap: Option<usize>,
    ignore_garbage: bool,
    decode: bool,
    name: &str
)
\ No newline at end of file diff --git a/uu_base32/base_common/fn.parse_base_cmd_args.html b/uu_base32/base_common/fn.parse_base_cmd_args.html new file mode 100644 index 000000000..4f7c53239 --- /dev/null +++ b/uu_base32/base_common/fn.parse_base_cmd_args.html @@ -0,0 +1,3 @@ +parse_base_cmd_args in uu_base32::base_common - Rust + +

Function uu_base32::base_common::parse_base_cmd_args[][src]

pub fn parse_base_cmd_args(
    args: impl Args,
    name: &str,
    version: &str,
    about: &str,
    usage: &str
) -> Result<Config, String>
\ No newline at end of file diff --git a/uu_base32/base_common/index.html b/uu_base32/base_common/index.html new file mode 100644 index 000000000..05c399878 --- /dev/null +++ b/uu_base32/base_common/index.html @@ -0,0 +1,6 @@ +uu_base32::base_common - Rust + +

Module uu_base32::base_common[][src]

Modules

+
options

Structs

+
Config

Functions

+
base_app
get_input
handle_input
parse_base_cmd_args
\ No newline at end of file diff --git a/uu_base32/base_common/options/index.html b/uu_base32/base_common/options/index.html new file mode 100644 index 000000000..0c20e7ced --- /dev/null +++ b/uu_base32/base_common/options/index.html @@ -0,0 +1,4 @@ +uu_base32::base_common::options - Rust + +

Module uu_base32::base_common::options[][src]

Statics

+
DECODE
FILE
IGNORE_GARBAGE
WRAP
\ No newline at end of file diff --git a/uu_base32/base_common/options/sidebar-items.js b/uu_base32/base_common/options/sidebar-items.js new file mode 100644 index 000000000..8dee405b2 --- /dev/null +++ b/uu_base32/base_common/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["DECODE",""],["FILE",""],["IGNORE_GARBAGE",""],["WRAP",""]]}); \ No newline at end of file diff --git a/uu_base32/base_common/options/static.DECODE.html b/uu_base32/base_common/options/static.DECODE.html new file mode 100644 index 000000000..787e63bbc --- /dev/null +++ b/uu_base32/base_common/options/static.DECODE.html @@ -0,0 +1,3 @@ +DECODE in uu_base32::base_common::options - Rust + +

Static uu_base32::base_common::options::DECODE[][src]

pub static DECODE: &str
\ No newline at end of file diff --git a/uu_base32/base_common/options/static.FILE.html b/uu_base32/base_common/options/static.FILE.html new file mode 100644 index 000000000..9a0a7b0ce --- /dev/null +++ b/uu_base32/base_common/options/static.FILE.html @@ -0,0 +1,3 @@ +FILE in uu_base32::base_common::options - Rust + +

Static uu_base32::base_common::options::FILE[][src]

pub static FILE: &str
\ No newline at end of file diff --git a/uu_base32/base_common/options/static.IGNORE_GARBAGE.html b/uu_base32/base_common/options/static.IGNORE_GARBAGE.html new file mode 100644 index 000000000..3685cee48 --- /dev/null +++ b/uu_base32/base_common/options/static.IGNORE_GARBAGE.html @@ -0,0 +1,3 @@ +IGNORE_GARBAGE in uu_base32::base_common::options - Rust + +

Static uu_base32::base_common::options::IGNORE_GARBAGE[][src]

pub static IGNORE_GARBAGE: &str
\ No newline at end of file diff --git a/uu_base32/base_common/options/static.WRAP.html b/uu_base32/base_common/options/static.WRAP.html new file mode 100644 index 000000000..f4cc795d2 --- /dev/null +++ b/uu_base32/base_common/options/static.WRAP.html @@ -0,0 +1,3 @@ +WRAP in uu_base32::base_common::options - Rust + +

Static uu_base32::base_common::options::WRAP[][src]

pub static WRAP: &str
\ No newline at end of file diff --git a/uu_base32/base_common/sidebar-items.js b/uu_base32/base_common/sidebar-items.js new file mode 100644 index 000000000..ffb550d47 --- /dev/null +++ b/uu_base32/base_common/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["base_app",""],["get_input",""],["handle_input",""],["parse_base_cmd_args",""]],"mod":[["options",""]],"struct":[["Config",""]]}); \ No newline at end of file diff --git a/uu_base32/base_common/struct.Config.html b/uu_base32/base_common/struct.Config.html new file mode 100644 index 000000000..3103ff093 --- /dev/null +++ b/uu_base32/base_common/struct.Config.html @@ -0,0 +1,18 @@ +Config in uu_base32::base_common - Rust + +

Struct uu_base32::base_common::Config[][src]

pub struct Config {
+    pub decode: bool,
+    pub ignore_garbage: bool,
+    pub wrap_cols: Option<usize>,
+    pub to_read: Option<String>,
+}

+ Fields

decode: boolignore_garbage: boolwrap_cols: Option<usize>to_read: Option<String>

Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_base32/fn.uu_app.html b/uu_base32/fn.uu_app.html new file mode 100644 index 000000000..5d2e2fac1 --- /dev/null +++ b/uu_base32/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_base32 - Rust + +

Function uu_base32::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_base32/fn.uumain.html b/uu_base32/fn.uumain.html new file mode 100644 index 000000000..2bbf1ac38 --- /dev/null +++ b/uu_base32/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_base32 - Rust + +

Function uu_base32::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_base32/index.html b/uu_base32/index.html new file mode 100644 index 000000000..10867123a --- /dev/null +++ b/uu_base32/index.html @@ -0,0 +1,5 @@ +uu_base32 - Rust + +

Crate uu_base32[][src]

Modules

+
base_common

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_base32/sidebar-items.js b/uu_base32/sidebar-items.js new file mode 100644 index 000000000..3254ad0dc --- /dev/null +++ b/uu_base32/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["base_common",""]]}); \ No newline at end of file diff --git a/uu_base64/all.html b/uu_base64/all.html new file mode 100644 index 000000000..632b0ec70 --- /dev/null +++ b/uu_base64/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_base64/fn.uu_app.html b/uu_base64/fn.uu_app.html new file mode 100644 index 000000000..cabebbc19 --- /dev/null +++ b/uu_base64/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_base64 - Rust + +

Function uu_base64::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_base64/fn.uumain.html b/uu_base64/fn.uumain.html new file mode 100644 index 000000000..17ab1985c --- /dev/null +++ b/uu_base64/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_base64 - Rust + +

Function uu_base64::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_base64/index.html b/uu_base64/index.html new file mode 100644 index 000000000..367454350 --- /dev/null +++ b/uu_base64/index.html @@ -0,0 +1,4 @@ +uu_base64 - Rust + +

Crate uu_base64[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_base64/sidebar-items.js b/uu_base64/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_base64/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_basename/all.html b/uu_basename/all.html new file mode 100644 index 000000000..350d36aae --- /dev/null +++ b/uu_basename/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_basename/fn.uu_app.html b/uu_basename/fn.uu_app.html new file mode 100644 index 000000000..f68000a4e --- /dev/null +++ b/uu_basename/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_basename - Rust + +

Function uu_basename::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_basename/fn.uumain.html b/uu_basename/fn.uumain.html new file mode 100644 index 000000000..9b2f3de57 --- /dev/null +++ b/uu_basename/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_basename - Rust + +

Function uu_basename::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_basename/index.html b/uu_basename/index.html new file mode 100644 index 000000000..80f4f7bdc --- /dev/null +++ b/uu_basename/index.html @@ -0,0 +1,5 @@ +uu_basename - Rust + +

Crate uu_basename[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_basename/options/index.html b/uu_basename/options/index.html new file mode 100644 index 000000000..8937693b0 --- /dev/null +++ b/uu_basename/options/index.html @@ -0,0 +1,4 @@ +uu_basename::options - Rust + +

Module uu_basename::options[][src]

Statics

+
MULTIPLE
NAME
SUFFIX
ZERO
\ No newline at end of file diff --git a/uu_basename/options/sidebar-items.js b/uu_basename/options/sidebar-items.js new file mode 100644 index 000000000..0d028f0a4 --- /dev/null +++ b/uu_basename/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["MULTIPLE",""],["NAME",""],["SUFFIX",""],["ZERO",""]]}); \ No newline at end of file diff --git a/uu_basename/options/static.MULTIPLE.html b/uu_basename/options/static.MULTIPLE.html new file mode 100644 index 000000000..5bce12a31 --- /dev/null +++ b/uu_basename/options/static.MULTIPLE.html @@ -0,0 +1,3 @@ +MULTIPLE in uu_basename::options - Rust + +

Static uu_basename::options::MULTIPLE[][src]

pub static MULTIPLE: &str
\ No newline at end of file diff --git a/uu_basename/options/static.NAME.html b/uu_basename/options/static.NAME.html new file mode 100644 index 000000000..15c8e9db9 --- /dev/null +++ b/uu_basename/options/static.NAME.html @@ -0,0 +1,3 @@ +NAME in uu_basename::options - Rust + +

Static uu_basename::options::NAME[][src]

pub static NAME: &str
\ No newline at end of file diff --git a/uu_basename/options/static.SUFFIX.html b/uu_basename/options/static.SUFFIX.html new file mode 100644 index 000000000..4dfb5b9c2 --- /dev/null +++ b/uu_basename/options/static.SUFFIX.html @@ -0,0 +1,3 @@ +SUFFIX in uu_basename::options - Rust + +

Static uu_basename::options::SUFFIX[][src]

pub static SUFFIX: &str
\ No newline at end of file diff --git a/uu_basename/options/static.ZERO.html b/uu_basename/options/static.ZERO.html new file mode 100644 index 000000000..ca37317df --- /dev/null +++ b/uu_basename/options/static.ZERO.html @@ -0,0 +1,3 @@ +ZERO in uu_basename::options - Rust + +

Static uu_basename::options::ZERO[][src]

pub static ZERO: &str
\ No newline at end of file diff --git a/uu_basename/sidebar-items.js b/uu_basename/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_basename/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_basenc/all.html b/uu_basenc/all.html new file mode 100644 index 000000000..a102f4e0a --- /dev/null +++ b/uu_basenc/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_basenc/fn.uu_app.html b/uu_basenc/fn.uu_app.html new file mode 100644 index 000000000..b7951b554 --- /dev/null +++ b/uu_basenc/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_basenc - Rust + +

Function uu_basenc::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_basenc/fn.uumain.html b/uu_basenc/fn.uumain.html new file mode 100644 index 000000000..d54a2f200 --- /dev/null +++ b/uu_basenc/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_basenc - Rust + +

Function uu_basenc::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_basenc/index.html b/uu_basenc/index.html new file mode 100644 index 000000000..45af80743 --- /dev/null +++ b/uu_basenc/index.html @@ -0,0 +1,4 @@ +uu_basenc - Rust + +

Crate uu_basenc[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_basenc/sidebar-items.js b/uu_basenc/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_basenc/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_cat/all.html b/uu_cat/all.html new file mode 100644 index 000000000..b1340fb75 --- /dev/null +++ b/uu_cat/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_cat/fn.uu_app.html b/uu_cat/fn.uu_app.html new file mode 100644 index 000000000..666f83190 --- /dev/null +++ b/uu_cat/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_cat - Rust + +

Function uu_cat::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_cat/fn.uumain.html b/uu_cat/fn.uumain.html new file mode 100644 index 000000000..0912af7b5 --- /dev/null +++ b/uu_cat/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_cat - Rust + +

Function uu_cat::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_cat/index.html b/uu_cat/index.html new file mode 100644 index 000000000..18cd26fa5 --- /dev/null +++ b/uu_cat/index.html @@ -0,0 +1,4 @@ +uu_cat - Rust + +

Crate uu_cat[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_cat/sidebar-items.js b/uu_cat/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_cat/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_chcon/all.html b/uu_chcon/all.html new file mode 100644 index 000000000..5a64b98cd --- /dev/null +++ b/uu_chcon/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_chcon/fn.uu_app.html b/uu_chcon/fn.uu_app.html new file mode 100644 index 000000000..44774859c --- /dev/null +++ b/uu_chcon/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_chcon - Rust + +

Function uu_chcon::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_chcon/fn.uumain.html b/uu_chcon/fn.uumain.html new file mode 100644 index 000000000..8d4e1f975 --- /dev/null +++ b/uu_chcon/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_chcon - Rust + +

Function uu_chcon::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_chcon/index.html b/uu_chcon/index.html new file mode 100644 index 000000000..78f451257 --- /dev/null +++ b/uu_chcon/index.html @@ -0,0 +1,5 @@ +uu_chcon - Rust + +

Crate uu_chcon[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_chcon/options/dereference/index.html b/uu_chcon/options/dereference/index.html new file mode 100644 index 000000000..1ec0ea0a9 --- /dev/null +++ b/uu_chcon/options/dereference/index.html @@ -0,0 +1,4 @@ +uu_chcon::options::dereference - Rust + +

Module uu_chcon::options::dereference[][src]

Statics

+
DEREFERENCE
NO_DEREFERENCE
\ No newline at end of file diff --git a/uu_chcon/options/dereference/sidebar-items.js b/uu_chcon/options/dereference/sidebar-items.js new file mode 100644 index 000000000..dc0806b40 --- /dev/null +++ b/uu_chcon/options/dereference/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["DEREFERENCE",""],["NO_DEREFERENCE",""]]}); \ No newline at end of file diff --git a/uu_chcon/options/dereference/static.DEREFERENCE.html b/uu_chcon/options/dereference/static.DEREFERENCE.html new file mode 100644 index 000000000..28e46f8e5 --- /dev/null +++ b/uu_chcon/options/dereference/static.DEREFERENCE.html @@ -0,0 +1,3 @@ +DEREFERENCE in uu_chcon::options::dereference - Rust + +

Static uu_chcon::options::dereference::DEREFERENCE[][src]

pub static DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_chcon/options/dereference/static.NO_DEREFERENCE.html b/uu_chcon/options/dereference/static.NO_DEREFERENCE.html new file mode 100644 index 000000000..78d1818b7 --- /dev/null +++ b/uu_chcon/options/dereference/static.NO_DEREFERENCE.html @@ -0,0 +1,3 @@ +NO_DEREFERENCE in uu_chcon::options::dereference - Rust + +

Static uu_chcon::options::dereference::NO_DEREFERENCE[][src]

pub static NO_DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_chcon/options/index.html b/uu_chcon/options/index.html new file mode 100644 index 000000000..16a65dc3a --- /dev/null +++ b/uu_chcon/options/index.html @@ -0,0 +1,5 @@ +uu_chcon::options - Rust + +

Module uu_chcon::options[][src]

Modules

+
dereference
preserve_root
sym_links

Statics

+
RANGE
RECURSIVE
REFERENCE
ROLE
TYPE
USER
VERBOSE
\ No newline at end of file diff --git a/uu_chcon/options/preserve_root/index.html b/uu_chcon/options/preserve_root/index.html new file mode 100644 index 000000000..d76c86e46 --- /dev/null +++ b/uu_chcon/options/preserve_root/index.html @@ -0,0 +1,4 @@ +uu_chcon::options::preserve_root - Rust + +

Module uu_chcon::options::preserve_root[][src]

Statics

+
NO_PRESERVE_ROOT
PRESERVE_ROOT
\ No newline at end of file diff --git a/uu_chcon/options/preserve_root/sidebar-items.js b/uu_chcon/options/preserve_root/sidebar-items.js new file mode 100644 index 000000000..9a112f7b4 --- /dev/null +++ b/uu_chcon/options/preserve_root/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["NO_PRESERVE_ROOT",""],["PRESERVE_ROOT",""]]}); \ No newline at end of file diff --git a/uu_chcon/options/preserve_root/static.NO_PRESERVE_ROOT.html b/uu_chcon/options/preserve_root/static.NO_PRESERVE_ROOT.html new file mode 100644 index 000000000..46b20ad17 --- /dev/null +++ b/uu_chcon/options/preserve_root/static.NO_PRESERVE_ROOT.html @@ -0,0 +1,3 @@ +NO_PRESERVE_ROOT in uu_chcon::options::preserve_root - Rust + +

Static uu_chcon::options::preserve_root::NO_PRESERVE_ROOT[][src]

pub static NO_PRESERVE_ROOT: &str
\ No newline at end of file diff --git a/uu_chcon/options/preserve_root/static.PRESERVE_ROOT.html b/uu_chcon/options/preserve_root/static.PRESERVE_ROOT.html new file mode 100644 index 000000000..2f45b5d46 --- /dev/null +++ b/uu_chcon/options/preserve_root/static.PRESERVE_ROOT.html @@ -0,0 +1,3 @@ +PRESERVE_ROOT in uu_chcon::options::preserve_root - Rust + +

Static uu_chcon::options::preserve_root::PRESERVE_ROOT[][src]

pub static PRESERVE_ROOT: &str
\ No newline at end of file diff --git a/uu_chcon/options/sidebar-items.js b/uu_chcon/options/sidebar-items.js new file mode 100644 index 000000000..3a5433974 --- /dev/null +++ b/uu_chcon/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["dereference",""],["preserve_root",""],["sym_links",""]],"static":[["RANGE",""],["RECURSIVE",""],["REFERENCE",""],["ROLE",""],["TYPE",""],["USER",""],["VERBOSE",""]]}); \ No newline at end of file diff --git a/uu_chcon/options/static.RANGE.html b/uu_chcon/options/static.RANGE.html new file mode 100644 index 000000000..6a7c85186 --- /dev/null +++ b/uu_chcon/options/static.RANGE.html @@ -0,0 +1,3 @@ +RANGE in uu_chcon::options - Rust + +

Static uu_chcon::options::RANGE[][src]

pub static RANGE: &str
\ No newline at end of file diff --git a/uu_chcon/options/static.RECURSIVE.html b/uu_chcon/options/static.RECURSIVE.html new file mode 100644 index 000000000..d83329f99 --- /dev/null +++ b/uu_chcon/options/static.RECURSIVE.html @@ -0,0 +1,3 @@ +RECURSIVE in uu_chcon::options - Rust + +

Static uu_chcon::options::RECURSIVE[][src]

pub static RECURSIVE: &str
\ No newline at end of file diff --git a/uu_chcon/options/static.REFERENCE.html b/uu_chcon/options/static.REFERENCE.html new file mode 100644 index 000000000..9179b6dea --- /dev/null +++ b/uu_chcon/options/static.REFERENCE.html @@ -0,0 +1,3 @@ +REFERENCE in uu_chcon::options - Rust + +

Static uu_chcon::options::REFERENCE[][src]

pub static REFERENCE: &str
\ No newline at end of file diff --git a/uu_chcon/options/static.ROLE.html b/uu_chcon/options/static.ROLE.html new file mode 100644 index 000000000..4c7a64cbc --- /dev/null +++ b/uu_chcon/options/static.ROLE.html @@ -0,0 +1,3 @@ +ROLE in uu_chcon::options - Rust + +

Static uu_chcon::options::ROLE[][src]

pub static ROLE: &str
\ No newline at end of file diff --git a/uu_chcon/options/static.TYPE.html b/uu_chcon/options/static.TYPE.html new file mode 100644 index 000000000..d67c7fbff --- /dev/null +++ b/uu_chcon/options/static.TYPE.html @@ -0,0 +1,3 @@ +TYPE in uu_chcon::options - Rust + +

Static uu_chcon::options::TYPE[][src]

pub static TYPE: &str
\ No newline at end of file diff --git a/uu_chcon/options/static.USER.html b/uu_chcon/options/static.USER.html new file mode 100644 index 000000000..5a436ac68 --- /dev/null +++ b/uu_chcon/options/static.USER.html @@ -0,0 +1,3 @@ +USER in uu_chcon::options - Rust + +

Static uu_chcon::options::USER[][src]

pub static USER: &str
\ No newline at end of file diff --git a/uu_chcon/options/static.VERBOSE.html b/uu_chcon/options/static.VERBOSE.html new file mode 100644 index 000000000..b62243f10 --- /dev/null +++ b/uu_chcon/options/static.VERBOSE.html @@ -0,0 +1,3 @@ +VERBOSE in uu_chcon::options - Rust + +

Static uu_chcon::options::VERBOSE[][src]

pub static VERBOSE: &str
\ No newline at end of file diff --git a/uu_chcon/options/sym_links/index.html b/uu_chcon/options/sym_links/index.html new file mode 100644 index 000000000..45c448536 --- /dev/null +++ b/uu_chcon/options/sym_links/index.html @@ -0,0 +1,4 @@ +uu_chcon::options::sym_links - Rust + +

Module uu_chcon::options::sym_links[][src]

Statics

+
FOLLOW_ARG_DIR_SYM_LINK
FOLLOW_DIR_SYM_LINKS
NO_FOLLOW_SYM_LINKS
\ No newline at end of file diff --git a/uu_chcon/options/sym_links/sidebar-items.js b/uu_chcon/options/sym_links/sidebar-items.js new file mode 100644 index 000000000..31938c8e8 --- /dev/null +++ b/uu_chcon/options/sym_links/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["FOLLOW_ARG_DIR_SYM_LINK",""],["FOLLOW_DIR_SYM_LINKS",""],["NO_FOLLOW_SYM_LINKS",""]]}); \ No newline at end of file diff --git a/uu_chcon/options/sym_links/static.FOLLOW_ARG_DIR_SYM_LINK.html b/uu_chcon/options/sym_links/static.FOLLOW_ARG_DIR_SYM_LINK.html new file mode 100644 index 000000000..36731e747 --- /dev/null +++ b/uu_chcon/options/sym_links/static.FOLLOW_ARG_DIR_SYM_LINK.html @@ -0,0 +1,3 @@ +FOLLOW_ARG_DIR_SYM_LINK in uu_chcon::options::sym_links - Rust + +

Static uu_chcon::options::sym_links::FOLLOW_ARG_DIR_SYM_LINK[][src]

pub static FOLLOW_ARG_DIR_SYM_LINK: &str
\ No newline at end of file diff --git a/uu_chcon/options/sym_links/static.FOLLOW_DIR_SYM_LINKS.html b/uu_chcon/options/sym_links/static.FOLLOW_DIR_SYM_LINKS.html new file mode 100644 index 000000000..32e34bd35 --- /dev/null +++ b/uu_chcon/options/sym_links/static.FOLLOW_DIR_SYM_LINKS.html @@ -0,0 +1,3 @@ +FOLLOW_DIR_SYM_LINKS in uu_chcon::options::sym_links - Rust + +

Static uu_chcon::options::sym_links::FOLLOW_DIR_SYM_LINKS[][src]

pub static FOLLOW_DIR_SYM_LINKS: &str
\ No newline at end of file diff --git a/uu_chcon/options/sym_links/static.NO_FOLLOW_SYM_LINKS.html b/uu_chcon/options/sym_links/static.NO_FOLLOW_SYM_LINKS.html new file mode 100644 index 000000000..7cf3217f0 --- /dev/null +++ b/uu_chcon/options/sym_links/static.NO_FOLLOW_SYM_LINKS.html @@ -0,0 +1,3 @@ +NO_FOLLOW_SYM_LINKS in uu_chcon::options::sym_links - Rust + +

Static uu_chcon::options::sym_links::NO_FOLLOW_SYM_LINKS[][src]

pub static NO_FOLLOW_SYM_LINKS: &str
\ No newline at end of file diff --git a/uu_chcon/sidebar-items.js b/uu_chcon/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_chcon/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_chgrp/all.html b/uu_chgrp/all.html new file mode 100644 index 000000000..5d85e8726 --- /dev/null +++ b/uu_chgrp/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Traits

Functions

Statics

\ No newline at end of file diff --git a/uu_chgrp/entries/fn.get_groups.html b/uu_chgrp/entries/fn.get_groups.html new file mode 100644 index 000000000..46d102376 --- /dev/null +++ b/uu_chgrp/entries/fn.get_groups.html @@ -0,0 +1,12 @@ +get_groups in uu_chgrp::entries - Rust + +

Function uu_chgrp::entries::get_groups[][src]

pub fn get_groups() -> Result<Vec<u32, Global>, Error>
Expand description

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
+

getgroups() returns the supplementary group IDs of the calling +process in list. +If size is zero, list is not modified, but the total number of +supplementary group IDs for the process is returned. This allows +the caller to determine the size of a dynamically allocated list +to be used in a further call to getgroups().

+
+
\ No newline at end of file diff --git a/uu_chgrp/entries/fn.get_groups_gnu.html b/uu_chgrp/entries/fn.get_groups_gnu.html new file mode 100644 index 000000000..38508f761 --- /dev/null +++ b/uu_chgrp/entries/fn.get_groups_gnu.html @@ -0,0 +1,25 @@ +get_groups_gnu in uu_chgrp::entries - Rust + +

Function uu_chgrp::entries::get_groups_gnu[][src]

pub fn get_groups_gnu(arg_id: Option<u32>) -> Result<Vec<u32, Global>, Error>
Expand description

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+

If arg_id is None (default), get_groups_gnu moves the effective +group id (egid) to the first entry in the returned Vector. +If arg_id is Some(x), get_groups_gnu moves the id with value x +to the first entry in the returned Vector. This might be necessary +for id --groups --real if gid and egid are not equal.

+

From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html

+
+

As implied by the definition of supplementary groups, the +effective group ID may appear in the array returned by +getgroups() or it may be returned only by getegid(). Duplication +may exist, but the application needs to call getegid() to be sure +of getting all of the information. Various implementation +variations and administrative sequences cause the set of groups +appearing in the result of getgroups() to vary in order and as to +whether the effective group ID is included, even when the set of +groups is the same (in the mathematical sense of ``set’’). (The +history of a process and its parents could affect the details of +the result.)

+
+
\ No newline at end of file diff --git a/uu_chgrp/entries/fn.gid2grp.html b/uu_chgrp/entries/fn.gid2grp.html new file mode 100644 index 000000000..2dbe51955 --- /dev/null +++ b/uu_chgrp/entries/fn.gid2grp.html @@ -0,0 +1,3 @@ +gid2grp in uu_chgrp::entries - Rust + +

Function uu_chgrp::entries::gid2grp[][src]

pub fn gid2grp(id: u32) -> Result<String, Error>
\ No newline at end of file diff --git a/uu_chgrp/entries/fn.grp2gid.html b/uu_chgrp/entries/fn.grp2gid.html new file mode 100644 index 000000000..544cc2b15 --- /dev/null +++ b/uu_chgrp/entries/fn.grp2gid.html @@ -0,0 +1,3 @@ +grp2gid in uu_chgrp::entries - Rust + +

Function uu_chgrp::entries::grp2gid[][src]

pub fn grp2gid(name: &str) -> Result<u32, Error>
\ No newline at end of file diff --git a/uu_chgrp/entries/fn.uid2usr.html b/uu_chgrp/entries/fn.uid2usr.html new file mode 100644 index 000000000..ac9a5eaee --- /dev/null +++ b/uu_chgrp/entries/fn.uid2usr.html @@ -0,0 +1,3 @@ +uid2usr in uu_chgrp::entries - Rust + +

Function uu_chgrp::entries::uid2usr[][src]

pub fn uid2usr(id: u32) -> Result<String, Error>
\ No newline at end of file diff --git a/uu_chgrp/entries/fn.usr2uid.html b/uu_chgrp/entries/fn.usr2uid.html new file mode 100644 index 000000000..228570089 --- /dev/null +++ b/uu_chgrp/entries/fn.usr2uid.html @@ -0,0 +1,3 @@ +usr2uid in uu_chgrp::entries - Rust + +

Function uu_chgrp::entries::usr2uid[][src]

pub fn usr2uid(name: &str) -> Result<u32, Error>
\ No newline at end of file diff --git a/uu_chgrp/entries/index.html b/uu_chgrp/entries/index.html new file mode 100644 index 000000000..25582b61e --- /dev/null +++ b/uu_chgrp/entries/index.html @@ -0,0 +1,34 @@ +uu_chgrp::entries - Rust + +

Module uu_chgrp::entries[][src]

Expand description

Get password/group file entry

+

Examples:

+
+use uucore::entries::{self, Locate};
+
+let root_group = if cfg!(any(target_os = "linux", target_os = "android")) {
+    "root"
+} else {
+    "wheel"
+};
+
+assert_eq!("root", entries::uid2usr(0).unwrap());
+assert_eq!(0, entries::usr2uid("root").unwrap());
+assert!(entries::gid2grp(0).is_ok());
+assert!(entries::grp2gid(root_group).is_ok());
+
+assert!(entries::Passwd::locate(0).is_ok());
+assert!(entries::Passwd::locate("0").is_ok());
+assert!(entries::Passwd::locate("root").is_ok());
+
+assert!(entries::Group::locate(0).is_ok());
+assert!(entries::Group::locate("0").is_ok());
+assert!(entries::Group::locate(root_group).is_ok());
+

Structs

+
Group
Passwd

Traits

+
Locate

Fetch desired entry.

+

Functions

+
get_groups

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
get_groups_gnu

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+
gid2grp
grp2gid
uid2usr
usr2uid
\ No newline at end of file diff --git a/uu_chgrp/entries/sidebar-items.js b/uu_chgrp/entries/sidebar-items.js new file mode 100644 index 000000000..55270684c --- /dev/null +++ b/uu_chgrp/entries/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_groups","From: https://man7.org/linux/man-pages/man2/getgroups.2.html"],["get_groups_gnu","The list of group IDs returned from GNU’s `groups` and GNU’s `id --groups` starts with the effective group ID (egid). This is a wrapper for `get_groups()` to mimic this behavior."],["gid2grp",""],["grp2gid",""],["uid2usr",""],["usr2uid",""]],"struct":[["Group",""],["Passwd",""]],"trait":[["Locate","Fetch desired entry."]]}); \ No newline at end of file diff --git a/uu_chgrp/entries/struct.Group.html b/uu_chgrp/entries/struct.Group.html new file mode 100644 index 000000000..68f7b63ae --- /dev/null +++ b/uu_chgrp/entries/struct.Group.html @@ -0,0 +1,14 @@ +Group in uu_chgrp::entries - Rust + +

Struct uu_chgrp::entries::Group[][src]

pub struct Group { /* fields omitted */ }

Implementations

AKA group.gr_name

+

AKA group.gr_gid

+

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_chgrp/entries/struct.Passwd.html b/uu_chgrp/entries/struct.Passwd.html new file mode 100644 index 000000000..c583f83af --- /dev/null +++ b/uu_chgrp/entries/struct.Passwd.html @@ -0,0 +1,39 @@ +Passwd in uu_chgrp::entries - Rust + +

Struct uu_chgrp::entries::Passwd[][src]

pub struct Passwd { /* fields omitted */ }

Implementations

AKA passwd.pw_name

+

AKA passwd.pw_uid

+

AKA passwd.pw_gid

+

AKA passwd.pw_gecos

+

AKA passwd.pw_shell

+

AKA passwd.pw_dir

+

AKA passwd.pw_passwd

+

This is a wrapper function for libc::getgrouplist.

+

From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html

+
+

If the number of groups of which user is a member is less than or +equal to *ngroups, then the value *ngroups is returned. +If the user is a member of more than *ngroups groups, then +getgrouplist() returns -1. In this case, the value returned in +*ngroups can be used to resize the buffer passed to a further +call getgrouplist().

+
+

However, on macOS/darwin (and maybe others?) getgrouplist does +not update ngroups if ngroups is too small. Therefore, if not +updated by getgrouplist, ngroups needs to be increased in a +loop until getgrouplist stops returning -1.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_chgrp/entries/trait.Locate.html b/uu_chgrp/entries/trait.Locate.html new file mode 100644 index 000000000..baba7008b --- /dev/null +++ b/uu_chgrp/entries/trait.Locate.html @@ -0,0 +1,6 @@ +Locate in uu_chgrp::entries - Rust + +

Trait uu_chgrp::entries::Locate[][src]

pub trait Locate<K> {
+    fn locate(key: K) -> Result<Self, Error>;
+}
Expand description

Fetch desired entry.

+

Required methods

Implementors

\ No newline at end of file diff --git a/uu_chgrp/fn.uu_app.html b/uu_chgrp/fn.uu_app.html new file mode 100644 index 000000000..5efd7d084 --- /dev/null +++ b/uu_chgrp/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_chgrp - Rust + +

Function uu_chgrp::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_chgrp/fn.uumain.html b/uu_chgrp/fn.uumain.html new file mode 100644 index 000000000..77f08df5a --- /dev/null +++ b/uu_chgrp/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_chgrp - Rust + +

Function uu_chgrp::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_chgrp/index.html b/uu_chgrp/index.html new file mode 100644 index 000000000..b47875f67 --- /dev/null +++ b/uu_chgrp/index.html @@ -0,0 +1,6 @@ +uu_chgrp - Rust + +

Crate uu_chgrp[][src]

Modules

+
entries

Get password/group file entry

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_chgrp/options/dereference/index.html b/uu_chgrp/options/dereference/index.html new file mode 100644 index 000000000..ec5723ff6 --- /dev/null +++ b/uu_chgrp/options/dereference/index.html @@ -0,0 +1,4 @@ +uu_chgrp::options::dereference - Rust + +

Module uu_chgrp::options::dereference[][src]

Statics

+
DEREFERENCE
NO_DEREFERENCE
\ No newline at end of file diff --git a/uu_chgrp/options/dereference/sidebar-items.js b/uu_chgrp/options/dereference/sidebar-items.js new file mode 100644 index 000000000..dc0806b40 --- /dev/null +++ b/uu_chgrp/options/dereference/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["DEREFERENCE",""],["NO_DEREFERENCE",""]]}); \ No newline at end of file diff --git a/uu_chgrp/options/dereference/static.DEREFERENCE.html b/uu_chgrp/options/dereference/static.DEREFERENCE.html new file mode 100644 index 000000000..f737c9737 --- /dev/null +++ b/uu_chgrp/options/dereference/static.DEREFERENCE.html @@ -0,0 +1,3 @@ +DEREFERENCE in uu_chgrp::options::dereference - Rust + +

Static uu_chgrp::options::dereference::DEREFERENCE[][src]

pub static DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/dereference/static.NO_DEREFERENCE.html b/uu_chgrp/options/dereference/static.NO_DEREFERENCE.html new file mode 100644 index 000000000..5d3840fd3 --- /dev/null +++ b/uu_chgrp/options/dereference/static.NO_DEREFERENCE.html @@ -0,0 +1,3 @@ +NO_DEREFERENCE in uu_chgrp::options::dereference - Rust + +

Static uu_chgrp::options::dereference::NO_DEREFERENCE[][src]

pub static NO_DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/index.html b/uu_chgrp/options/index.html new file mode 100644 index 000000000..fba92e2e9 --- /dev/null +++ b/uu_chgrp/options/index.html @@ -0,0 +1,5 @@ +uu_chgrp::options - Rust + +

Module uu_chgrp::options[][src]

Modules

+
dereference
preserve_root
traverse
verbosity

Statics

+
ARG_FILES
ARG_GROUP
RECURSIVE
REFERENCE
\ No newline at end of file diff --git a/uu_chgrp/options/preserve_root/index.html b/uu_chgrp/options/preserve_root/index.html new file mode 100644 index 000000000..495c7f546 --- /dev/null +++ b/uu_chgrp/options/preserve_root/index.html @@ -0,0 +1,4 @@ +uu_chgrp::options::preserve_root - Rust + +

Module uu_chgrp::options::preserve_root[][src]

Statics

+
NO_PRESERVE
PRESERVE
\ No newline at end of file diff --git a/uu_chgrp/options/preserve_root/sidebar-items.js b/uu_chgrp/options/preserve_root/sidebar-items.js new file mode 100644 index 000000000..e08f1649a --- /dev/null +++ b/uu_chgrp/options/preserve_root/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["NO_PRESERVE",""],["PRESERVE",""]]}); \ No newline at end of file diff --git a/uu_chgrp/options/preserve_root/static.NO_PRESERVE.html b/uu_chgrp/options/preserve_root/static.NO_PRESERVE.html new file mode 100644 index 000000000..3ead404ab --- /dev/null +++ b/uu_chgrp/options/preserve_root/static.NO_PRESERVE.html @@ -0,0 +1,3 @@ +NO_PRESERVE in uu_chgrp::options::preserve_root - Rust + +

Static uu_chgrp::options::preserve_root::NO_PRESERVE[][src]

pub static NO_PRESERVE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/preserve_root/static.PRESERVE.html b/uu_chgrp/options/preserve_root/static.PRESERVE.html new file mode 100644 index 000000000..c59a02f08 --- /dev/null +++ b/uu_chgrp/options/preserve_root/static.PRESERVE.html @@ -0,0 +1,3 @@ +PRESERVE in uu_chgrp::options::preserve_root - Rust + +

Static uu_chgrp::options::preserve_root::PRESERVE[][src]

pub static PRESERVE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/sidebar-items.js b/uu_chgrp/options/sidebar-items.js new file mode 100644 index 000000000..2f06c5e10 --- /dev/null +++ b/uu_chgrp/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["dereference",""],["preserve_root",""],["traverse",""],["verbosity",""]],"static":[["ARG_FILES",""],["ARG_GROUP",""],["RECURSIVE",""],["REFERENCE",""]]}); \ No newline at end of file diff --git a/uu_chgrp/options/static.ARG_FILES.html b/uu_chgrp/options/static.ARG_FILES.html new file mode 100644 index 000000000..623809c80 --- /dev/null +++ b/uu_chgrp/options/static.ARG_FILES.html @@ -0,0 +1,3 @@ +ARG_FILES in uu_chgrp::options - Rust + +

Static uu_chgrp::options::ARG_FILES[][src]

pub static ARG_FILES: &str
\ No newline at end of file diff --git a/uu_chgrp/options/static.ARG_GROUP.html b/uu_chgrp/options/static.ARG_GROUP.html new file mode 100644 index 000000000..c19478d5e --- /dev/null +++ b/uu_chgrp/options/static.ARG_GROUP.html @@ -0,0 +1,3 @@ +ARG_GROUP in uu_chgrp::options - Rust + +

Static uu_chgrp::options::ARG_GROUP[][src]

pub static ARG_GROUP: &str
\ No newline at end of file diff --git a/uu_chgrp/options/static.RECURSIVE.html b/uu_chgrp/options/static.RECURSIVE.html new file mode 100644 index 000000000..743e7ee53 --- /dev/null +++ b/uu_chgrp/options/static.RECURSIVE.html @@ -0,0 +1,3 @@ +RECURSIVE in uu_chgrp::options - Rust + +

Static uu_chgrp::options::RECURSIVE[][src]

pub static RECURSIVE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/static.REFERENCE.html b/uu_chgrp/options/static.REFERENCE.html new file mode 100644 index 000000000..9abf46160 --- /dev/null +++ b/uu_chgrp/options/static.REFERENCE.html @@ -0,0 +1,3 @@ +REFERENCE in uu_chgrp::options - Rust + +

Static uu_chgrp::options::REFERENCE[][src]

pub static REFERENCE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/traverse/index.html b/uu_chgrp/options/traverse/index.html new file mode 100644 index 000000000..494989b42 --- /dev/null +++ b/uu_chgrp/options/traverse/index.html @@ -0,0 +1,4 @@ +uu_chgrp::options::traverse - Rust + +

Module uu_chgrp::options::traverse[][src]

Statics

+
EVERY
NO_TRAVERSE
TRAVERSE
\ No newline at end of file diff --git a/uu_chgrp/options/traverse/sidebar-items.js b/uu_chgrp/options/traverse/sidebar-items.js new file mode 100644 index 000000000..0461bc68b --- /dev/null +++ b/uu_chgrp/options/traverse/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["EVERY",""],["NO_TRAVERSE",""],["TRAVERSE",""]]}); \ No newline at end of file diff --git a/uu_chgrp/options/traverse/static.EVERY.html b/uu_chgrp/options/traverse/static.EVERY.html new file mode 100644 index 000000000..4411480ee --- /dev/null +++ b/uu_chgrp/options/traverse/static.EVERY.html @@ -0,0 +1,3 @@ +EVERY in uu_chgrp::options::traverse - Rust + +

Static uu_chgrp::options::traverse::EVERY[][src]

pub static EVERY: &str
\ No newline at end of file diff --git a/uu_chgrp/options/traverse/static.NO_TRAVERSE.html b/uu_chgrp/options/traverse/static.NO_TRAVERSE.html new file mode 100644 index 000000000..32a1dae2a --- /dev/null +++ b/uu_chgrp/options/traverse/static.NO_TRAVERSE.html @@ -0,0 +1,3 @@ +NO_TRAVERSE in uu_chgrp::options::traverse - Rust + +

Static uu_chgrp::options::traverse::NO_TRAVERSE[][src]

pub static NO_TRAVERSE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/traverse/static.TRAVERSE.html b/uu_chgrp/options/traverse/static.TRAVERSE.html new file mode 100644 index 000000000..b30cea811 --- /dev/null +++ b/uu_chgrp/options/traverse/static.TRAVERSE.html @@ -0,0 +1,3 @@ +TRAVERSE in uu_chgrp::options::traverse - Rust + +

Static uu_chgrp::options::traverse::TRAVERSE[][src]

pub static TRAVERSE: &str
\ No newline at end of file diff --git a/uu_chgrp/options/verbosity/index.html b/uu_chgrp/options/verbosity/index.html new file mode 100644 index 000000000..b9f908fb3 --- /dev/null +++ b/uu_chgrp/options/verbosity/index.html @@ -0,0 +1,4 @@ +uu_chgrp::options::verbosity - Rust + +

Module uu_chgrp::options::verbosity[][src]

Statics

+
CHANGES
QUIET
SILENT
VERBOSE
\ No newline at end of file diff --git a/uu_chgrp/options/verbosity/sidebar-items.js b/uu_chgrp/options/verbosity/sidebar-items.js new file mode 100644 index 000000000..e3bcc591e --- /dev/null +++ b/uu_chgrp/options/verbosity/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["CHANGES",""],["QUIET",""],["SILENT",""],["VERBOSE",""]]}); \ No newline at end of file diff --git a/uu_chgrp/options/verbosity/static.CHANGES.html b/uu_chgrp/options/verbosity/static.CHANGES.html new file mode 100644 index 000000000..1557ec566 --- /dev/null +++ b/uu_chgrp/options/verbosity/static.CHANGES.html @@ -0,0 +1,3 @@ +CHANGES in uu_chgrp::options::verbosity - Rust + +

Static uu_chgrp::options::verbosity::CHANGES[][src]

pub static CHANGES: &str
\ No newline at end of file diff --git a/uu_chgrp/options/verbosity/static.QUIET.html b/uu_chgrp/options/verbosity/static.QUIET.html new file mode 100644 index 000000000..1682ac8b5 --- /dev/null +++ b/uu_chgrp/options/verbosity/static.QUIET.html @@ -0,0 +1,3 @@ +QUIET in uu_chgrp::options::verbosity - Rust + +

Static uu_chgrp::options::verbosity::QUIET[][src]

pub static QUIET: &str
\ No newline at end of file diff --git a/uu_chgrp/options/verbosity/static.SILENT.html b/uu_chgrp/options/verbosity/static.SILENT.html new file mode 100644 index 000000000..5d308eb3c --- /dev/null +++ b/uu_chgrp/options/verbosity/static.SILENT.html @@ -0,0 +1,3 @@ +SILENT in uu_chgrp::options::verbosity - Rust + +

Static uu_chgrp::options::verbosity::SILENT[][src]

pub static SILENT: &str
\ No newline at end of file diff --git a/uu_chgrp/options/verbosity/static.VERBOSE.html b/uu_chgrp/options/verbosity/static.VERBOSE.html new file mode 100644 index 000000000..746c972e5 --- /dev/null +++ b/uu_chgrp/options/verbosity/static.VERBOSE.html @@ -0,0 +1,3 @@ +VERBOSE in uu_chgrp::options::verbosity - Rust + +

Static uu_chgrp::options::verbosity::VERBOSE[][src]

pub static VERBOSE: &str
\ No newline at end of file diff --git a/uu_chgrp/sidebar-items.js b/uu_chgrp/sidebar-items.js new file mode 100644 index 000000000..3ead3cbbc --- /dev/null +++ b/uu_chgrp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["entries","Get password/group file entry"],["options",""]]}); \ No newline at end of file diff --git a/uu_chmod/all.html b/uu_chmod/all.html new file mode 100644 index 000000000..af6b908aa --- /dev/null +++ b/uu_chmod/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_chmod/fn.is_symlink.html b/uu_chmod/fn.is_symlink.html new file mode 100644 index 000000000..da9699a3d --- /dev/null +++ b/uu_chmod/fn.is_symlink.html @@ -0,0 +1,3 @@ +is_symlink in uu_chmod - Rust + +

Function uu_chmod::is_symlink[][src]

pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool
\ No newline at end of file diff --git a/uu_chmod/fn.strip_minus_from_mode.html b/uu_chmod/fn.strip_minus_from_mode.html new file mode 100644 index 000000000..cd1254a9c --- /dev/null +++ b/uu_chmod/fn.strip_minus_from_mode.html @@ -0,0 +1,3 @@ +strip_minus_from_mode in uu_chmod - Rust + +

Function uu_chmod::strip_minus_from_mode[][src]

pub fn strip_minus_from_mode(args: &mut Vec<String>) -> bool
\ No newline at end of file diff --git a/uu_chmod/fn.uu_app.html b/uu_chmod/fn.uu_app.html new file mode 100644 index 000000000..66a14d4a4 --- /dev/null +++ b/uu_chmod/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_chmod - Rust + +

Function uu_chmod::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_chmod/fn.uumain.html b/uu_chmod/fn.uumain.html new file mode 100644 index 000000000..998659364 --- /dev/null +++ b/uu_chmod/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_chmod - Rust + +

Function uu_chmod::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_chmod/index.html b/uu_chmod/index.html new file mode 100644 index 000000000..f15134ef8 --- /dev/null +++ b/uu_chmod/index.html @@ -0,0 +1,4 @@ +uu_chmod - Rust + +

Crate uu_chmod[][src]

Functions

+
is_symlink
strip_minus_from_mode
uu_app
uumain
\ No newline at end of file diff --git a/uu_chmod/sidebar-items.js b/uu_chmod/sidebar-items.js new file mode 100644 index 000000000..cdb75cac1 --- /dev/null +++ b/uu_chmod/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["is_symlink",""],["strip_minus_from_mode",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_chown/all.html b/uu_chown/all.html new file mode 100644 index 000000000..27373d38e --- /dev/null +++ b/uu_chown/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Traits

Functions

Statics

\ No newline at end of file diff --git a/uu_chown/entries/fn.get_groups.html b/uu_chown/entries/fn.get_groups.html new file mode 100644 index 000000000..d27d08d9f --- /dev/null +++ b/uu_chown/entries/fn.get_groups.html @@ -0,0 +1,12 @@ +get_groups in uu_chown::entries - Rust + +

Function uu_chown::entries::get_groups[][src]

pub fn get_groups() -> Result<Vec<u32, Global>, Error>
Expand description

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
+

getgroups() returns the supplementary group IDs of the calling +process in list. +If size is zero, list is not modified, but the total number of +supplementary group IDs for the process is returned. This allows +the caller to determine the size of a dynamically allocated list +to be used in a further call to getgroups().

+
+
\ No newline at end of file diff --git a/uu_chown/entries/fn.get_groups_gnu.html b/uu_chown/entries/fn.get_groups_gnu.html new file mode 100644 index 000000000..29657e89c --- /dev/null +++ b/uu_chown/entries/fn.get_groups_gnu.html @@ -0,0 +1,25 @@ +get_groups_gnu in uu_chown::entries - Rust + +

Function uu_chown::entries::get_groups_gnu[][src]

pub fn get_groups_gnu(arg_id: Option<u32>) -> Result<Vec<u32, Global>, Error>
Expand description

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+

If arg_id is None (default), get_groups_gnu moves the effective +group id (egid) to the first entry in the returned Vector. +If arg_id is Some(x), get_groups_gnu moves the id with value x +to the first entry in the returned Vector. This might be necessary +for id --groups --real if gid and egid are not equal.

+

From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html

+
+

As implied by the definition of supplementary groups, the +effective group ID may appear in the array returned by +getgroups() or it may be returned only by getegid(). Duplication +may exist, but the application needs to call getegid() to be sure +of getting all of the information. Various implementation +variations and administrative sequences cause the set of groups +appearing in the result of getgroups() to vary in order and as to +whether the effective group ID is included, even when the set of +groups is the same (in the mathematical sense of ``set’’). (The +history of a process and its parents could affect the details of +the result.)

+
+
\ No newline at end of file diff --git a/uu_chown/entries/fn.gid2grp.html b/uu_chown/entries/fn.gid2grp.html new file mode 100644 index 000000000..44e093404 --- /dev/null +++ b/uu_chown/entries/fn.gid2grp.html @@ -0,0 +1,3 @@ +gid2grp in uu_chown::entries - Rust + +

Function uu_chown::entries::gid2grp[][src]

pub fn gid2grp(id: u32) -> Result<String, Error>
\ No newline at end of file diff --git a/uu_chown/entries/fn.grp2gid.html b/uu_chown/entries/fn.grp2gid.html new file mode 100644 index 000000000..4b8bbdcd9 --- /dev/null +++ b/uu_chown/entries/fn.grp2gid.html @@ -0,0 +1,3 @@ +grp2gid in uu_chown::entries - Rust + +

Function uu_chown::entries::grp2gid[][src]

pub fn grp2gid(name: &str) -> Result<u32, Error>
\ No newline at end of file diff --git a/uu_chown/entries/fn.uid2usr.html b/uu_chown/entries/fn.uid2usr.html new file mode 100644 index 000000000..ea34c6925 --- /dev/null +++ b/uu_chown/entries/fn.uid2usr.html @@ -0,0 +1,3 @@ +uid2usr in uu_chown::entries - Rust + +

Function uu_chown::entries::uid2usr[][src]

pub fn uid2usr(id: u32) -> Result<String, Error>
\ No newline at end of file diff --git a/uu_chown/entries/fn.usr2uid.html b/uu_chown/entries/fn.usr2uid.html new file mode 100644 index 000000000..04ab1681d --- /dev/null +++ b/uu_chown/entries/fn.usr2uid.html @@ -0,0 +1,3 @@ +usr2uid in uu_chown::entries - Rust + +

Function uu_chown::entries::usr2uid[][src]

pub fn usr2uid(name: &str) -> Result<u32, Error>
\ No newline at end of file diff --git a/uu_chown/entries/index.html b/uu_chown/entries/index.html new file mode 100644 index 000000000..3e7f80d34 --- /dev/null +++ b/uu_chown/entries/index.html @@ -0,0 +1,34 @@ +uu_chown::entries - Rust + +

Module uu_chown::entries[][src]

Expand description

Get password/group file entry

+

Examples:

+
+use uucore::entries::{self, Locate};
+
+let root_group = if cfg!(any(target_os = "linux", target_os = "android")) {
+    "root"
+} else {
+    "wheel"
+};
+
+assert_eq!("root", entries::uid2usr(0).unwrap());
+assert_eq!(0, entries::usr2uid("root").unwrap());
+assert!(entries::gid2grp(0).is_ok());
+assert!(entries::grp2gid(root_group).is_ok());
+
+assert!(entries::Passwd::locate(0).is_ok());
+assert!(entries::Passwd::locate("0").is_ok());
+assert!(entries::Passwd::locate("root").is_ok());
+
+assert!(entries::Group::locate(0).is_ok());
+assert!(entries::Group::locate("0").is_ok());
+assert!(entries::Group::locate(root_group).is_ok());
+

Structs

+
Group
Passwd

Traits

+
Locate

Fetch desired entry.

+

Functions

+
get_groups

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
get_groups_gnu

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+
gid2grp
grp2gid
uid2usr
usr2uid
\ No newline at end of file diff --git a/uu_chown/entries/sidebar-items.js b/uu_chown/entries/sidebar-items.js new file mode 100644 index 000000000..55270684c --- /dev/null +++ b/uu_chown/entries/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_groups","From: https://man7.org/linux/man-pages/man2/getgroups.2.html"],["get_groups_gnu","The list of group IDs returned from GNU’s `groups` and GNU’s `id --groups` starts with the effective group ID (egid). This is a wrapper for `get_groups()` to mimic this behavior."],["gid2grp",""],["grp2gid",""],["uid2usr",""],["usr2uid",""]],"struct":[["Group",""],["Passwd",""]],"trait":[["Locate","Fetch desired entry."]]}); \ No newline at end of file diff --git a/uu_chown/entries/struct.Group.html b/uu_chown/entries/struct.Group.html new file mode 100644 index 000000000..6ca2b10a4 --- /dev/null +++ b/uu_chown/entries/struct.Group.html @@ -0,0 +1,14 @@ +Group in uu_chown::entries - Rust + +

Struct uu_chown::entries::Group[][src]

pub struct Group { /* fields omitted */ }

Implementations

AKA group.gr_name

+

AKA group.gr_gid

+

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_chown/entries/struct.Passwd.html b/uu_chown/entries/struct.Passwd.html new file mode 100644 index 000000000..2408ab687 --- /dev/null +++ b/uu_chown/entries/struct.Passwd.html @@ -0,0 +1,39 @@ +Passwd in uu_chown::entries - Rust + +

Struct uu_chown::entries::Passwd[][src]

pub struct Passwd { /* fields omitted */ }

Implementations

AKA passwd.pw_name

+

AKA passwd.pw_uid

+

AKA passwd.pw_gid

+

AKA passwd.pw_gecos

+

AKA passwd.pw_shell

+

AKA passwd.pw_dir

+

AKA passwd.pw_passwd

+

This is a wrapper function for libc::getgrouplist.

+

From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html

+
+

If the number of groups of which user is a member is less than or +equal to *ngroups, then the value *ngroups is returned. +If the user is a member of more than *ngroups groups, then +getgrouplist() returns -1. In this case, the value returned in +*ngroups can be used to resize the buffer passed to a further +call getgrouplist().

+
+

However, on macOS/darwin (and maybe others?) getgrouplist does +not update ngroups if ngroups is too small. Therefore, if not +updated by getgrouplist, ngroups needs to be increased in a +loop until getgrouplist stops returning -1.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_chown/entries/trait.Locate.html b/uu_chown/entries/trait.Locate.html new file mode 100644 index 000000000..e6967f223 --- /dev/null +++ b/uu_chown/entries/trait.Locate.html @@ -0,0 +1,6 @@ +Locate in uu_chown::entries - Rust + +

Trait uu_chown::entries::Locate[][src]

pub trait Locate<K> {
+    fn locate(key: K) -> Result<Self, Error>;
+}
Expand description

Fetch desired entry.

+

Required methods

Implementors

\ No newline at end of file diff --git a/uu_chown/fn.uu_app.html b/uu_chown/fn.uu_app.html new file mode 100644 index 000000000..43f12fe01 --- /dev/null +++ b/uu_chown/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_chown - Rust + +

Function uu_chown::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_chown/fn.uumain.html b/uu_chown/fn.uumain.html new file mode 100644 index 000000000..0a7b3533c --- /dev/null +++ b/uu_chown/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_chown - Rust + +

Function uu_chown::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_chown/index.html b/uu_chown/index.html new file mode 100644 index 000000000..a0b3be1b3 --- /dev/null +++ b/uu_chown/index.html @@ -0,0 +1,9 @@ +uu_chown - Rust + +

Crate uu_chown[][src]

Modules

+
entries

Get password/group file entry

+
options

Structs

+
Group
Passwd

Traits

+
Locate

Fetch desired entry.

+

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_chown/options/dereference/index.html b/uu_chown/options/dereference/index.html new file mode 100644 index 000000000..5112fa274 --- /dev/null +++ b/uu_chown/options/dereference/index.html @@ -0,0 +1,4 @@ +uu_chown::options::dereference - Rust + +

Module uu_chown::options::dereference[][src]

Statics

+
DEREFERENCE
NO_DEREFERENCE
\ No newline at end of file diff --git a/uu_chown/options/dereference/sidebar-items.js b/uu_chown/options/dereference/sidebar-items.js new file mode 100644 index 000000000..dc0806b40 --- /dev/null +++ b/uu_chown/options/dereference/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["DEREFERENCE",""],["NO_DEREFERENCE",""]]}); \ No newline at end of file diff --git a/uu_chown/options/dereference/static.DEREFERENCE.html b/uu_chown/options/dereference/static.DEREFERENCE.html new file mode 100644 index 000000000..1be71f395 --- /dev/null +++ b/uu_chown/options/dereference/static.DEREFERENCE.html @@ -0,0 +1,3 @@ +DEREFERENCE in uu_chown::options::dereference - Rust + +

Static uu_chown::options::dereference::DEREFERENCE[][src]

pub static DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_chown/options/dereference/static.NO_DEREFERENCE.html b/uu_chown/options/dereference/static.NO_DEREFERENCE.html new file mode 100644 index 000000000..6abfd84c2 --- /dev/null +++ b/uu_chown/options/dereference/static.NO_DEREFERENCE.html @@ -0,0 +1,3 @@ +NO_DEREFERENCE in uu_chown::options::dereference - Rust + +

Static uu_chown::options::dereference::NO_DEREFERENCE[][src]

pub static NO_DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_chown/options/index.html b/uu_chown/options/index.html new file mode 100644 index 000000000..e475d3dd9 --- /dev/null +++ b/uu_chown/options/index.html @@ -0,0 +1,5 @@ +uu_chown::options - Rust + +

Module uu_chown::options[][src]

Modules

+
dereference
preserve_root
traverse
verbosity

Statics

+
FROM
RECURSIVE
REFERENCE
\ No newline at end of file diff --git a/uu_chown/options/preserve_root/index.html b/uu_chown/options/preserve_root/index.html new file mode 100644 index 000000000..f7467eedd --- /dev/null +++ b/uu_chown/options/preserve_root/index.html @@ -0,0 +1,4 @@ +uu_chown::options::preserve_root - Rust + +

Module uu_chown::options::preserve_root[][src]

Statics

+
NO_PRESERVE
PRESERVE
\ No newline at end of file diff --git a/uu_chown/options/preserve_root/sidebar-items.js b/uu_chown/options/preserve_root/sidebar-items.js new file mode 100644 index 000000000..e08f1649a --- /dev/null +++ b/uu_chown/options/preserve_root/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["NO_PRESERVE",""],["PRESERVE",""]]}); \ No newline at end of file diff --git a/uu_chown/options/preserve_root/static.NO_PRESERVE.html b/uu_chown/options/preserve_root/static.NO_PRESERVE.html new file mode 100644 index 000000000..1e4e9975b --- /dev/null +++ b/uu_chown/options/preserve_root/static.NO_PRESERVE.html @@ -0,0 +1,3 @@ +NO_PRESERVE in uu_chown::options::preserve_root - Rust + +

Static uu_chown::options::preserve_root::NO_PRESERVE[][src]

pub static NO_PRESERVE: &str
\ No newline at end of file diff --git a/uu_chown/options/preserve_root/static.PRESERVE.html b/uu_chown/options/preserve_root/static.PRESERVE.html new file mode 100644 index 000000000..c2f528071 --- /dev/null +++ b/uu_chown/options/preserve_root/static.PRESERVE.html @@ -0,0 +1,3 @@ +PRESERVE in uu_chown::options::preserve_root - Rust + +

Static uu_chown::options::preserve_root::PRESERVE[][src]

pub static PRESERVE: &str
\ No newline at end of file diff --git a/uu_chown/options/sidebar-items.js b/uu_chown/options/sidebar-items.js new file mode 100644 index 000000000..de74d2b25 --- /dev/null +++ b/uu_chown/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["dereference",""],["preserve_root",""],["traverse",""],["verbosity",""]],"static":[["FROM",""],["RECURSIVE",""],["REFERENCE",""]]}); \ No newline at end of file diff --git a/uu_chown/options/static.FROM.html b/uu_chown/options/static.FROM.html new file mode 100644 index 000000000..a42fc46ef --- /dev/null +++ b/uu_chown/options/static.FROM.html @@ -0,0 +1,3 @@ +FROM in uu_chown::options - Rust + +

Static uu_chown::options::FROM[][src]

pub static FROM: &str
\ No newline at end of file diff --git a/uu_chown/options/static.RECURSIVE.html b/uu_chown/options/static.RECURSIVE.html new file mode 100644 index 000000000..a62ec1155 --- /dev/null +++ b/uu_chown/options/static.RECURSIVE.html @@ -0,0 +1,3 @@ +RECURSIVE in uu_chown::options - Rust + +

Static uu_chown::options::RECURSIVE[][src]

pub static RECURSIVE: &str
\ No newline at end of file diff --git a/uu_chown/options/static.REFERENCE.html b/uu_chown/options/static.REFERENCE.html new file mode 100644 index 000000000..cbcd80c04 --- /dev/null +++ b/uu_chown/options/static.REFERENCE.html @@ -0,0 +1,3 @@ +REFERENCE in uu_chown::options - Rust + +

Static uu_chown::options::REFERENCE[][src]

pub static REFERENCE: &str
\ No newline at end of file diff --git a/uu_chown/options/traverse/index.html b/uu_chown/options/traverse/index.html new file mode 100644 index 000000000..dd61961b0 --- /dev/null +++ b/uu_chown/options/traverse/index.html @@ -0,0 +1,4 @@ +uu_chown::options::traverse - Rust + +

Module uu_chown::options::traverse[][src]

Statics

+
EVERY
NO_TRAVERSE
TRAVERSE
\ No newline at end of file diff --git a/uu_chown/options/traverse/sidebar-items.js b/uu_chown/options/traverse/sidebar-items.js new file mode 100644 index 000000000..0461bc68b --- /dev/null +++ b/uu_chown/options/traverse/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["EVERY",""],["NO_TRAVERSE",""],["TRAVERSE",""]]}); \ No newline at end of file diff --git a/uu_chown/options/traverse/static.EVERY.html b/uu_chown/options/traverse/static.EVERY.html new file mode 100644 index 000000000..9c0c49b47 --- /dev/null +++ b/uu_chown/options/traverse/static.EVERY.html @@ -0,0 +1,3 @@ +EVERY in uu_chown::options::traverse - Rust + +

Static uu_chown::options::traverse::EVERY[][src]

pub static EVERY: &str
\ No newline at end of file diff --git a/uu_chown/options/traverse/static.NO_TRAVERSE.html b/uu_chown/options/traverse/static.NO_TRAVERSE.html new file mode 100644 index 000000000..88a77c366 --- /dev/null +++ b/uu_chown/options/traverse/static.NO_TRAVERSE.html @@ -0,0 +1,3 @@ +NO_TRAVERSE in uu_chown::options::traverse - Rust + +

Static uu_chown::options::traverse::NO_TRAVERSE[][src]

pub static NO_TRAVERSE: &str
\ No newline at end of file diff --git a/uu_chown/options/traverse/static.TRAVERSE.html b/uu_chown/options/traverse/static.TRAVERSE.html new file mode 100644 index 000000000..55ffb2421 --- /dev/null +++ b/uu_chown/options/traverse/static.TRAVERSE.html @@ -0,0 +1,3 @@ +TRAVERSE in uu_chown::options::traverse - Rust + +

Static uu_chown::options::traverse::TRAVERSE[][src]

pub static TRAVERSE: &str
\ No newline at end of file diff --git a/uu_chown/options/verbosity/index.html b/uu_chown/options/verbosity/index.html new file mode 100644 index 000000000..4401c679f --- /dev/null +++ b/uu_chown/options/verbosity/index.html @@ -0,0 +1,4 @@ +uu_chown::options::verbosity - Rust + +

Module uu_chown::options::verbosity[][src]

Statics

+
CHANGES
QUIET
SILENT
VERBOSE
\ No newline at end of file diff --git a/uu_chown/options/verbosity/sidebar-items.js b/uu_chown/options/verbosity/sidebar-items.js new file mode 100644 index 000000000..e3bcc591e --- /dev/null +++ b/uu_chown/options/verbosity/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["CHANGES",""],["QUIET",""],["SILENT",""],["VERBOSE",""]]}); \ No newline at end of file diff --git a/uu_chown/options/verbosity/static.CHANGES.html b/uu_chown/options/verbosity/static.CHANGES.html new file mode 100644 index 000000000..c8673367b --- /dev/null +++ b/uu_chown/options/verbosity/static.CHANGES.html @@ -0,0 +1,3 @@ +CHANGES in uu_chown::options::verbosity - Rust + +

Static uu_chown::options::verbosity::CHANGES[][src]

pub static CHANGES: &str
\ No newline at end of file diff --git a/uu_chown/options/verbosity/static.QUIET.html b/uu_chown/options/verbosity/static.QUIET.html new file mode 100644 index 000000000..b440ff635 --- /dev/null +++ b/uu_chown/options/verbosity/static.QUIET.html @@ -0,0 +1,3 @@ +QUIET in uu_chown::options::verbosity - Rust + +

Static uu_chown::options::verbosity::QUIET[][src]

pub static QUIET: &str
\ No newline at end of file diff --git a/uu_chown/options/verbosity/static.SILENT.html b/uu_chown/options/verbosity/static.SILENT.html new file mode 100644 index 000000000..8dc760e9a --- /dev/null +++ b/uu_chown/options/verbosity/static.SILENT.html @@ -0,0 +1,3 @@ +SILENT in uu_chown::options::verbosity - Rust + +

Static uu_chown::options::verbosity::SILENT[][src]

pub static SILENT: &str
\ No newline at end of file diff --git a/uu_chown/options/verbosity/static.VERBOSE.html b/uu_chown/options/verbosity/static.VERBOSE.html new file mode 100644 index 000000000..e3b61b35f --- /dev/null +++ b/uu_chown/options/verbosity/static.VERBOSE.html @@ -0,0 +1,3 @@ +VERBOSE in uu_chown::options::verbosity - Rust + +

Static uu_chown::options::verbosity::VERBOSE[][src]

pub static VERBOSE: &str
\ No newline at end of file diff --git a/uu_chown/sidebar-items.js b/uu_chown/sidebar-items.js new file mode 100644 index 000000000..f123da64c --- /dev/null +++ b/uu_chown/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["entries","Get password/group file entry"],["options",""]],"struct":[["Group",""],["Passwd",""]],"trait":[["Locate","Fetch desired entry."]]}); \ No newline at end of file diff --git a/uu_chown/struct.Group.html b/uu_chown/struct.Group.html new file mode 100644 index 000000000..942aab404 --- /dev/null +++ b/uu_chown/struct.Group.html @@ -0,0 +1,14 @@ +Group in uu_chown - Rust + +

Struct uu_chown::Group[][src]

pub struct Group { /* fields omitted */ }

Implementations

AKA group.gr_name

+

AKA group.gr_gid

+

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_chown/struct.Passwd.html b/uu_chown/struct.Passwd.html new file mode 100644 index 000000000..8f40ec1ca --- /dev/null +++ b/uu_chown/struct.Passwd.html @@ -0,0 +1,39 @@ +Passwd in uu_chown - Rust + +

Struct uu_chown::Passwd[][src]

pub struct Passwd { /* fields omitted */ }

Implementations

AKA passwd.pw_name

+

AKA passwd.pw_uid

+

AKA passwd.pw_gid

+

AKA passwd.pw_gecos

+

AKA passwd.pw_shell

+

AKA passwd.pw_dir

+

AKA passwd.pw_passwd

+

This is a wrapper function for libc::getgrouplist.

+

From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html

+
+

If the number of groups of which user is a member is less than or +equal to *ngroups, then the value *ngroups is returned. +If the user is a member of more than *ngroups groups, then +getgrouplist() returns -1. In this case, the value returned in +*ngroups can be used to resize the buffer passed to a further +call getgrouplist().

+
+

However, on macOS/darwin (and maybe others?) getgrouplist does +not update ngroups if ngroups is too small. Therefore, if not +updated by getgrouplist, ngroups needs to be increased in a +loop until getgrouplist stops returning -1.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_chown/trait.Locate.html b/uu_chown/trait.Locate.html new file mode 100644 index 000000000..bb1598bad --- /dev/null +++ b/uu_chown/trait.Locate.html @@ -0,0 +1,6 @@ +Locate in uu_chown - Rust + +

Trait uu_chown::Locate[][src]

pub trait Locate<K> {
+    fn locate(key: K) -> Result<Self, Error>;
+}
Expand description

Fetch desired entry.

+

Required methods

Implementors

\ No newline at end of file diff --git a/uu_chroot/all.html b/uu_chroot/all.html new file mode 100644 index 000000000..9d3b98eaa --- /dev/null +++ b/uu_chroot/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_chroot/fn.uu_app.html b/uu_chroot/fn.uu_app.html new file mode 100644 index 000000000..dae7edaec --- /dev/null +++ b/uu_chroot/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_chroot - Rust + +

Function uu_chroot::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_chroot/fn.uumain.html b/uu_chroot/fn.uumain.html new file mode 100644 index 000000000..a6af6370b --- /dev/null +++ b/uu_chroot/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_chroot - Rust + +

Function uu_chroot::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_chroot/index.html b/uu_chroot/index.html new file mode 100644 index 000000000..1f1b1fe82 --- /dev/null +++ b/uu_chroot/index.html @@ -0,0 +1,4 @@ +uu_chroot - Rust + +

Crate uu_chroot[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_chroot/sidebar-items.js b/uu_chroot/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_chroot/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_cksum/all.html b/uu_cksum/all.html new file mode 100644 index 000000000..cb4ec6b44 --- /dev/null +++ b/uu_cksum/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_cksum/fn.uu_app.html b/uu_cksum/fn.uu_app.html new file mode 100644 index 000000000..41995073c --- /dev/null +++ b/uu_cksum/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_cksum - Rust + +

Function uu_cksum::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_cksum/fn.uumain.html b/uu_cksum/fn.uumain.html new file mode 100644 index 000000000..621d41409 --- /dev/null +++ b/uu_cksum/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_cksum - Rust + +

Function uu_cksum::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_cksum/index.html b/uu_cksum/index.html new file mode 100644 index 000000000..7bb3e1c02 --- /dev/null +++ b/uu_cksum/index.html @@ -0,0 +1,4 @@ +uu_cksum - Rust + +

Crate uu_cksum[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_cksum/sidebar-items.js b/uu_cksum/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_cksum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_comm/all.html b/uu_comm/all.html new file mode 100644 index 000000000..0c15f4f45 --- /dev/null +++ b/uu_comm/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_comm/fn.uu_app.html b/uu_comm/fn.uu_app.html new file mode 100644 index 000000000..efccca047 --- /dev/null +++ b/uu_comm/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_comm - Rust + +

Function uu_comm::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_comm/fn.uumain.html b/uu_comm/fn.uumain.html new file mode 100644 index 000000000..f828bb7b5 --- /dev/null +++ b/uu_comm/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_comm - Rust + +

Function uu_comm::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_comm/index.html b/uu_comm/index.html new file mode 100644 index 000000000..1f5b1bc5a --- /dev/null +++ b/uu_comm/index.html @@ -0,0 +1,4 @@ +uu_comm - Rust + +

Crate uu_comm[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_comm/sidebar-items.js b/uu_comm/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_comm/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_cp/all.html b/uu_cp/all.html new file mode 100644 index 000000000..c988e2e1f --- /dev/null +++ b/uu_cp/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Functions

Typedefs

\ No newline at end of file diff --git a/uu_cp/enum.Attribute.html b/uu_cp/enum.Attribute.html new file mode 100644 index 000000000..a76587605 --- /dev/null +++ b/uu_cp/enum.Attribute.html @@ -0,0 +1,32 @@ +Attribute in uu_cp - Rust + +

Enum uu_cp::Attribute[][src]

pub enum Attribute {
+    Mode,
+    Ownership,
+    Timestamps,
+    Context,
+    Links,
+    Xattr,
+}

+ Variants

+
Mode
Ownership
Timestamps
Context
Xattr

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/enum.ClobberMode.html b/uu_cp/enum.ClobberMode.html new file mode 100644 index 000000000..97343c91c --- /dev/null +++ b/uu_cp/enum.ClobberMode.html @@ -0,0 +1,28 @@ +ClobberMode in uu_cp - Rust + +

Enum uu_cp::ClobberMode[][src]

pub enum ClobberMode {
+    Force,
+    RemoveDestination,
+    Standard,
+}
Expand description

Specifies whether when overwrite files

+

+ Variants

+
Force
RemoveDestination
Standard

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/enum.CopyMode.html b/uu_cp/enum.CopyMode.html new file mode 100644 index 000000000..e92f54d77 --- /dev/null +++ b/uu_cp/enum.CopyMode.html @@ -0,0 +1,21 @@ +CopyMode in uu_cp - Rust + +

Enum uu_cp::CopyMode[][src]

pub enum CopyMode {
+    Link,
+    SymLink,
+    Sparse,
+    Copy,
+    Update,
+    AttrOnly,
+}

+ Variants

+
Sparse
Copy
Update
AttrOnly

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/enum.Error.html b/uu_cp/enum.Error.html new file mode 100644 index 000000000..a46509ce4 --- /dev/null +++ b/uu_cp/enum.Error.html @@ -0,0 +1,51 @@ +Error in uu_cp - Rust + +

Enum uu_cp::Error[][src]

pub enum Error {
+    IoErr(Error),
+    IoErrContext(ErrorString),
+    Error(String),
+    NotAllFilesCopied,
+    WalkDirErr(Error),
+    StripPrefixError(StripPrefixError),
+    Skipped(String),
+    InvalidArgument(String),
+    NotImplemented(String),
+    Backup(String),
+}

+ Variants

+
IoErr(Error)

Simple io::Error wrapper

+
IoErrContext(ErrorString)

Wrapper for io::Error with path context

+
Error(String)

General copy error

+
NotAllFilesCopied

Represents the state when a non-fatal error has occurred +and not all files were copied.

+
WalkDirErr(Error)

Simple walkdir::Error wrapper

+
StripPrefixError(StripPrefixError)

Simple std::path::StripPrefixError wrapper

+
Skipped(String)

Result of a skipped file

+
InvalidArgument(String)

Result of a skipped file

+
NotImplemented(String)

All standard options are included as an an implementation +path, but those that are not implemented yet should return +a NotImplemented error.

+
Backup(String)

Invalid arguments to backup

+

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/enum.OverwriteMode.html b/uu_cp/enum.OverwriteMode.html new file mode 100644 index 000000000..b22cb0e8f --- /dev/null +++ b/uu_cp/enum.OverwriteMode.html @@ -0,0 +1,31 @@ +OverwriteMode in uu_cp - Rust + +

Enum uu_cp::OverwriteMode[][src]

pub enum OverwriteMode {
+    Clobber(ClobberMode),
+    Interactive(ClobberMode),
+    NoClobber,
+}
Expand description

Specifies whether when overwrite files

+

+ Variants

+
Clobber(ClobberMode)

Default Always overwrite existing files

+
Interactive(ClobberMode)

Prompt before overwriting a file

+
NoClobber

Never overwrite a file

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/enum.ReflinkMode.html b/uu_cp/enum.ReflinkMode.html new file mode 100644 index 000000000..e9db08fc7 --- /dev/null +++ b/uu_cp/enum.ReflinkMode.html @@ -0,0 +1,28 @@ +ReflinkMode in uu_cp - Rust + +

Enum uu_cp::ReflinkMode[][src]

pub enum ReflinkMode {
+    Always,
+    Auto,
+    Never,
+}
Expand description

Possible arguments for --reflink.

+

+ Variants

+
Always
Auto
Never

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/enum.TargetType.html b/uu_cp/enum.TargetType.html new file mode 100644 index 000000000..2dd4d766c --- /dev/null +++ b/uu_cp/enum.TargetType.html @@ -0,0 +1,18 @@ +TargetType in uu_cp - Rust + +

Enum uu_cp::TargetType[][src]

pub enum TargetType {
+    Directory,
+    File,
+}
Expand description

Specifies the expected file type of copy target

+

+ Variants

+
Directory
File

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/fn.ficlone.html b/uu_cp/fn.ficlone.html new file mode 100644 index 000000000..3e8ed7a08 --- /dev/null +++ b/uu_cp/fn.ficlone.html @@ -0,0 +1,3 @@ +ficlone in uu_cp - Rust + +

Function uu_cp::ficlone[][src]

pub unsafe fn ficlone(fd: c_int, val: *const c_int) -> c_int
\ No newline at end of file diff --git a/uu_cp/fn.localize_to_target.html b/uu_cp/fn.localize_to_target.html new file mode 100644 index 000000000..148ffd8ac --- /dev/null +++ b/uu_cp/fn.localize_to_target.html @@ -0,0 +1,12 @@ +localize_to_target in uu_cp - Rust + +

Function uu_cp::localize_to_target[][src]

pub fn localize_to_target(
    root: &Path,
    source: &Path,
    target: &Path
) -> CopyResult<PathBuf>
Expand description

Remove the root prefix from source and prefix it with target +to create a file that is local to target

+

Examples

+
+assert!(uu_cp::localize_to_target(
+    &Path::new("a/source/"),
+    &Path::new("a/source/c.txt"),
+    &Path::new("target/"),
+).unwrap() == Path::new("target/c.txt"))
+
\ No newline at end of file diff --git a/uu_cp/fn.paths_refer_to_same_file.html b/uu_cp/fn.paths_refer_to_same_file.html new file mode 100644 index 000000000..58f92e2c9 --- /dev/null +++ b/uu_cp/fn.paths_refer_to_same_file.html @@ -0,0 +1,3 @@ +paths_refer_to_same_file in uu_cp - Rust + +

Function uu_cp::paths_refer_to_same_file[][src]

pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> Result<bool>
\ No newline at end of file diff --git a/uu_cp/fn.uu_app.html b/uu_cp/fn.uu_app.html new file mode 100644 index 000000000..d2a8ccc5e --- /dev/null +++ b/uu_cp/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_cp - Rust + +

Function uu_cp::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_cp/fn.uumain.html b/uu_cp/fn.uumain.html new file mode 100644 index 000000000..84fbd46e6 --- /dev/null +++ b/uu_cp/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_cp - Rust + +

Function uu_cp::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_cp/fn.verify_target_type.html b/uu_cp/fn.verify_target_type.html new file mode 100644 index 000000000..c2193d432 --- /dev/null +++ b/uu_cp/fn.verify_target_type.html @@ -0,0 +1,4 @@ +verify_target_type in uu_cp - Rust + +

Function uu_cp::verify_target_type[][src]

pub fn verify_target_type(
    target: &Path,
    target_type: &TargetType
) -> CopyResult<()>
Expand description

Generate an error message if target is not the correct target_type

+
\ No newline at end of file diff --git a/uu_cp/index.html b/uu_cp/index.html new file mode 100644 index 000000000..9ce087e8a --- /dev/null +++ b/uu_cp/index.html @@ -0,0 +1,15 @@ +uu_cp - Rust + +

Crate uu_cp[][src]

Structs

+
Options

Re-usable, extensible copy options

+

Enums

+
Attribute
ClobberMode

Specifies whether when overwrite files

+
CopyMode
Error
OverwriteMode

Specifies whether when overwrite files

+
ReflinkMode

Possible arguments for --reflink.

+
TargetType

Specifies the expected file type of copy target

+

Functions

+
ficlone
localize_to_target

Remove the root prefix from source and prefix it with target +to create a file that is local to target

+
paths_refer_to_same_file
uu_app
uumain
verify_target_type

Generate an error message if target is not the correct target_type

+

Type Definitions

+
CopyResult
Source
SourceSlice
Target
TargetSlice
\ No newline at end of file diff --git a/uu_cp/sidebar-items.js b/uu_cp/sidebar-items.js new file mode 100644 index 000000000..7da5667b4 --- /dev/null +++ b/uu_cp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Attribute",""],["ClobberMode","Specifies whether when overwrite files"],["CopyMode",""],["Error",""],["OverwriteMode","Specifies whether when overwrite files"],["ReflinkMode","Possible arguments for `--reflink`."],["TargetType","Specifies the expected file type of copy target"]],"fn":[["ficlone",""],["localize_to_target","Remove the `root` prefix from `source` and prefix it with `target` to create a file that is local to `target`"],["paths_refer_to_same_file",""],["uu_app",""],["uumain",""],["verify_target_type","Generate an error message if `target` is not the correct `target_type`"]],"struct":[["Options","Re-usable, extensible copy options"]],"type":[["CopyResult",""],["Source",""],["SourceSlice",""],["Target",""],["TargetSlice",""]]}); \ No newline at end of file diff --git a/uu_cp/struct.Options.html b/uu_cp/struct.Options.html new file mode 100644 index 000000000..366aea3ec --- /dev/null +++ b/uu_cp/struct.Options.html @@ -0,0 +1,13 @@ +Options in uu_cp - Rust + +

Struct uu_cp::Options[][src]

pub struct Options { /* fields omitted */ }
Expand description

Re-usable, extensible copy options

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cp/type.CopyResult.html b/uu_cp/type.CopyResult.html new file mode 100644 index 000000000..939d3d423 --- /dev/null +++ b/uu_cp/type.CopyResult.html @@ -0,0 +1,3 @@ +CopyResult in uu_cp - Rust + +

Type Definition uu_cp::CopyResult[][src]

type CopyResult<T> = Result<T, Error>;
\ No newline at end of file diff --git a/uu_cp/type.Source.html b/uu_cp/type.Source.html new file mode 100644 index 000000000..97deab1be --- /dev/null +++ b/uu_cp/type.Source.html @@ -0,0 +1,3 @@ +Source in uu_cp - Rust + +

Type Definition uu_cp::Source[][src]

type Source = PathBuf;
\ No newline at end of file diff --git a/uu_cp/type.SourceSlice.html b/uu_cp/type.SourceSlice.html new file mode 100644 index 000000000..4dd902781 --- /dev/null +++ b/uu_cp/type.SourceSlice.html @@ -0,0 +1,3 @@ +SourceSlice in uu_cp - Rust + +

Type Definition uu_cp::SourceSlice[][src]

type SourceSlice = Path;
\ No newline at end of file diff --git a/uu_cp/type.Target.html b/uu_cp/type.Target.html new file mode 100644 index 000000000..c77c37173 --- /dev/null +++ b/uu_cp/type.Target.html @@ -0,0 +1,3 @@ +Target in uu_cp - Rust + +

Type Definition uu_cp::Target[][src]

type Target = PathBuf;
\ No newline at end of file diff --git a/uu_cp/type.TargetSlice.html b/uu_cp/type.TargetSlice.html new file mode 100644 index 000000000..fcdb07a8e --- /dev/null +++ b/uu_cp/type.TargetSlice.html @@ -0,0 +1,3 @@ +TargetSlice in uu_cp - Rust + +

Type Definition uu_cp::TargetSlice[][src]

type TargetSlice = Path;
\ No newline at end of file diff --git a/uu_csplit/all.html b/uu_csplit/all.html new file mode 100644 index 000000000..837cb6b23 --- /dev/null +++ b/uu_csplit/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Functions

\ No newline at end of file diff --git a/uu_csplit/fn.csplit.html b/uu_csplit/fn.csplit.html new file mode 100644 index 000000000..45bbbcdac --- /dev/null +++ b/uu_csplit/fn.csplit.html @@ -0,0 +1,15 @@ +csplit in uu_csplit - Rust + +

Function uu_csplit::csplit[][src]

pub fn csplit<T>(
    options: &CsplitOptions,
    patterns: Vec<Pattern>,
    input: T
) -> Result<(), CsplitError> where
    T: BufRead
Expand description

Splits a file into severals according to the command line patterns.

+

Errors

+
    +
  • io::Error if there is some problem reading/writing from/to a file.
  • +
  • [::CsplitError::LineOutOfRange] if the line number pattern is larger than the number of input +lines.
  • +
  • [::CsplitError::LineOutOfRangeOnRepetition], like previous but after applying the pattern +more than once.
  • +
  • [::CsplitError::MatchNotFound] if no line matched a regular expression.
  • +
  • [::CsplitError::MatchNotFoundOnRepetition], like previous but after applying the pattern +more than once.
  • +
+
\ No newline at end of file diff --git a/uu_csplit/fn.uu_app.html b/uu_csplit/fn.uu_app.html new file mode 100644 index 000000000..21ac9d8c7 --- /dev/null +++ b/uu_csplit/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_csplit - Rust + +

Function uu_csplit::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_csplit/fn.uumain.html b/uu_csplit/fn.uumain.html new file mode 100644 index 000000000..2a42bbec6 --- /dev/null +++ b/uu_csplit/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_csplit - Rust + +

Function uu_csplit::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_csplit/index.html b/uu_csplit/index.html new file mode 100644 index 000000000..05587fa9a --- /dev/null +++ b/uu_csplit/index.html @@ -0,0 +1,7 @@ +uu_csplit - Rust + +

Crate uu_csplit[][src]

Structs

+
CsplitOptions

Command line options for csplit.

+

Functions

+
csplit

Splits a file into severals according to the command line patterns.

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_csplit/sidebar-items.js b/uu_csplit/sidebar-items.js new file mode 100644 index 000000000..c8ec30868 --- /dev/null +++ b/uu_csplit/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["csplit","Splits a file into severals according to the command line patterns."],["uu_app",""],["uumain",""]],"struct":[["CsplitOptions","Command line options for csplit."]]}); \ No newline at end of file diff --git a/uu_csplit/struct.CsplitOptions.html b/uu_csplit/struct.CsplitOptions.html new file mode 100644 index 000000000..214784521 --- /dev/null +++ b/uu_csplit/struct.CsplitOptions.html @@ -0,0 +1,13 @@ +CsplitOptions in uu_csplit - Rust + +

Struct uu_csplit::CsplitOptions[][src]

pub struct CsplitOptions { /* fields omitted */ }
Expand description

Command line options for csplit.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_cut/all.html b/uu_cut/all.html new file mode 100644 index 000000000..929429340 --- /dev/null +++ b/uu_cut/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_cut/fn.uu_app.html b/uu_cut/fn.uu_app.html new file mode 100644 index 000000000..b03665996 --- /dev/null +++ b/uu_cut/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_cut - Rust + +

Function uu_cut::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_cut/fn.uumain.html b/uu_cut/fn.uumain.html new file mode 100644 index 000000000..90df1a00d --- /dev/null +++ b/uu_cut/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_cut - Rust + +

Function uu_cut::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_cut/index.html b/uu_cut/index.html new file mode 100644 index 000000000..23654ec10 --- /dev/null +++ b/uu_cut/index.html @@ -0,0 +1,4 @@ +uu_cut - Rust + +

Crate uu_cut[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_cut/sidebar-items.js b/uu_cut/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_cut/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_date/all.html b/uu_date/all.html new file mode 100644 index 000000000..eaf069408 --- /dev/null +++ b/uu_date/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_date/fn.uu_app.html b/uu_date/fn.uu_app.html new file mode 100644 index 000000000..32bda4959 --- /dev/null +++ b/uu_date/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_date - Rust + +

Function uu_date::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_date/fn.uumain.html b/uu_date/fn.uumain.html new file mode 100644 index 000000000..505581922 --- /dev/null +++ b/uu_date/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_date - Rust + +

Function uu_date::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_date/index.html b/uu_date/index.html new file mode 100644 index 000000000..ebad8596f --- /dev/null +++ b/uu_date/index.html @@ -0,0 +1,4 @@ +uu_date - Rust + +

Crate uu_date[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_date/sidebar-items.js b/uu_date/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_date/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_dd/all.html b/uu_dd/all.html new file mode 100644 index 000000000..08e447570 --- /dev/null +++ b/uu_dd/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_dd/fn.uu_app.html b/uu_dd/fn.uu_app.html new file mode 100644 index 000000000..aa63e419b --- /dev/null +++ b/uu_dd/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_dd - Rust + +

Function uu_dd::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_dd/fn.uumain.html b/uu_dd/fn.uumain.html new file mode 100644 index 000000000..0b8b0ab31 --- /dev/null +++ b/uu_dd/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_dd - Rust + +

Function uu_dd::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_dd/index.html b/uu_dd/index.html new file mode 100644 index 000000000..a82ea29af --- /dev/null +++ b/uu_dd/index.html @@ -0,0 +1,4 @@ +uu_dd - Rust + +

Crate uu_dd[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_dd/sidebar-items.js b/uu_dd/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_dd/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_df/all.html b/uu_df/all.html new file mode 100644 index 000000000..5d0ac1075 --- /dev/null +++ b/uu_df/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_df/fn.uu_app.html b/uu_df/fn.uu_app.html new file mode 100644 index 000000000..923fd0989 --- /dev/null +++ b/uu_df/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_df - Rust + +

Function uu_df::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_df/fn.uumain.html b/uu_df/fn.uumain.html new file mode 100644 index 000000000..15a87ae89 --- /dev/null +++ b/uu_df/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_df - Rust + +

Function uu_df::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_df/index.html b/uu_df/index.html new file mode 100644 index 000000000..b6c482e8d --- /dev/null +++ b/uu_df/index.html @@ -0,0 +1,4 @@ +uu_df - Rust + +

Crate uu_df[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_df/sidebar-items.js b/uu_df/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_df/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_dircolors/all.html b/uu_dircolors/all.html new file mode 100644 index 000000000..aafd43dd1 --- /dev/null +++ b/uu_dircolors/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Enums

Traits

Functions

\ No newline at end of file diff --git a/uu_dircolors/enum.OutputFmt.html b/uu_dircolors/enum.OutputFmt.html new file mode 100644 index 000000000..11850a425 --- /dev/null +++ b/uu_dircolors/enum.OutputFmt.html @@ -0,0 +1,22 @@ +OutputFmt in uu_dircolors - Rust + +

Enum uu_dircolors::OutputFmt[][src]

pub enum OutputFmt {
+    Shell,
+    CShell,
+    Unknown,
+}

+ Variants

+
Shell
CShell
Unknown

Trait Implementations

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_dircolors/fn.guess_syntax.html b/uu_dircolors/fn.guess_syntax.html new file mode 100644 index 000000000..3fea148ab --- /dev/null +++ b/uu_dircolors/fn.guess_syntax.html @@ -0,0 +1,3 @@ +guess_syntax in uu_dircolors - Rust + +

Function uu_dircolors::guess_syntax[][src]

pub fn guess_syntax() -> OutputFmt
\ No newline at end of file diff --git a/uu_dircolors/fn.uu_app.html b/uu_dircolors/fn.uu_app.html new file mode 100644 index 000000000..5f7bfb67b --- /dev/null +++ b/uu_dircolors/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_dircolors - Rust + +

Function uu_dircolors::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_dircolors/fn.uumain.html b/uu_dircolors/fn.uumain.html new file mode 100644 index 000000000..2cba6c5ef --- /dev/null +++ b/uu_dircolors/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_dircolors - Rust + +

Function uu_dircolors::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_dircolors/index.html b/uu_dircolors/index.html new file mode 100644 index 000000000..2d8f1a8a2 --- /dev/null +++ b/uu_dircolors/index.html @@ -0,0 +1,6 @@ +uu_dircolors - Rust + +

Crate uu_dircolors[][src]

Enums

+
OutputFmt

Traits

+
StrUtils

Functions

+
guess_syntax
uu_app
uumain
\ No newline at end of file diff --git a/uu_dircolors/sidebar-items.js b/uu_dircolors/sidebar-items.js new file mode 100644 index 000000000..e76f8b9ab --- /dev/null +++ b/uu_dircolors/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["OutputFmt",""]],"fn":[["guess_syntax",""],["uu_app",""],["uumain",""]],"trait":[["StrUtils",""]]}); \ No newline at end of file diff --git a/uu_dircolors/trait.StrUtils.html b/uu_dircolors/trait.StrUtils.html new file mode 100644 index 000000000..d56e2c47e --- /dev/null +++ b/uu_dircolors/trait.StrUtils.html @@ -0,0 +1,9 @@ +StrUtils in uu_dircolors - Rust + +

Trait uu_dircolors::StrUtils[][src]

pub trait StrUtils {
+    fn purify(&self) -> &Self;
+
fn split_two(&self) -> (&str, &str); +
fn fnmatch(&self, pattern: &str) -> bool; +}

Required methods

Remove comments and trim whitespace

+

Like split_whitespace() but only produce 2 components

+

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/uu_dirname/all.html b/uu_dirname/all.html new file mode 100644 index 000000000..2120f4d87 --- /dev/null +++ b/uu_dirname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_dirname/fn.uu_app.html b/uu_dirname/fn.uu_app.html new file mode 100644 index 000000000..7b0d024b0 --- /dev/null +++ b/uu_dirname/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_dirname - Rust + +

Function uu_dirname::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_dirname/fn.uumain.html b/uu_dirname/fn.uumain.html new file mode 100644 index 000000000..053132add --- /dev/null +++ b/uu_dirname/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_dirname - Rust + +

Function uu_dirname::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_dirname/index.html b/uu_dirname/index.html new file mode 100644 index 000000000..4a5421fea --- /dev/null +++ b/uu_dirname/index.html @@ -0,0 +1,4 @@ +uu_dirname - Rust + +

Crate uu_dirname[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_dirname/sidebar-items.js b/uu_dirname/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_dirname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_du/all.html b/uu_du/all.html new file mode 100644 index 000000000..a06925af2 --- /dev/null +++ b/uu_du/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_du/fn.uu_app.html b/uu_du/fn.uu_app.html new file mode 100644 index 000000000..8d0e0249e --- /dev/null +++ b/uu_du/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_du - Rust + +

Function uu_du::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_du/fn.uumain.html b/uu_du/fn.uumain.html new file mode 100644 index 000000000..6581984dd --- /dev/null +++ b/uu_du/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_du - Rust + +

Function uu_du::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_du/index.html b/uu_du/index.html new file mode 100644 index 000000000..afb1861d5 --- /dev/null +++ b/uu_du/index.html @@ -0,0 +1,4 @@ +uu_du - Rust + +

Crate uu_du[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_du/sidebar-items.js b/uu_du/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_du/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_echo/all.html b/uu_echo/all.html new file mode 100644 index 000000000..e59284ff1 --- /dev/null +++ b/uu_echo/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_echo/fn.uu_app.html b/uu_echo/fn.uu_app.html new file mode 100644 index 000000000..b0beb4462 --- /dev/null +++ b/uu_echo/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_echo - Rust + +

Function uu_echo::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_echo/fn.uumain.html b/uu_echo/fn.uumain.html new file mode 100644 index 000000000..17f85d219 --- /dev/null +++ b/uu_echo/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_echo - Rust + +

Function uu_echo::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_echo/index.html b/uu_echo/index.html new file mode 100644 index 000000000..4958bde9e --- /dev/null +++ b/uu_echo/index.html @@ -0,0 +1,4 @@ +uu_echo - Rust + +

Crate uu_echo[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_echo/sidebar-items.js b/uu_echo/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_echo/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_env/all.html b/uu_env/all.html new file mode 100644 index 000000000..5329d8fe7 --- /dev/null +++ b/uu_env/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_env/fn.uu_app.html b/uu_env/fn.uu_app.html new file mode 100644 index 000000000..dc6a736da --- /dev/null +++ b/uu_env/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_env - Rust + +

Function uu_env::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_env/fn.uumain.html b/uu_env/fn.uumain.html new file mode 100644 index 000000000..ff3a794dc --- /dev/null +++ b/uu_env/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_env - Rust + +

Function uu_env::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_env/index.html b/uu_env/index.html new file mode 100644 index 000000000..41282a250 --- /dev/null +++ b/uu_env/index.html @@ -0,0 +1,4 @@ +uu_env - Rust + +

Crate uu_env[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_env/sidebar-items.js b/uu_env/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_env/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_expand/all.html b/uu_expand/all.html new file mode 100644 index 000000000..54a4f3934 --- /dev/null +++ b/uu_expand/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_expand/fn.uu_app.html b/uu_expand/fn.uu_app.html new file mode 100644 index 000000000..1fbc8577f --- /dev/null +++ b/uu_expand/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_expand - Rust + +

Function uu_expand::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_expand/fn.uumain.html b/uu_expand/fn.uumain.html new file mode 100644 index 000000000..ef9163ff3 --- /dev/null +++ b/uu_expand/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_expand - Rust + +

Function uu_expand::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_expand/index.html b/uu_expand/index.html new file mode 100644 index 000000000..04de32ed8 --- /dev/null +++ b/uu_expand/index.html @@ -0,0 +1,5 @@ +uu_expand - Rust + +

Crate uu_expand[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_expand/options/index.html b/uu_expand/options/index.html new file mode 100644 index 000000000..347e89f0e --- /dev/null +++ b/uu_expand/options/index.html @@ -0,0 +1,4 @@ +uu_expand::options - Rust + +

Module uu_expand::options[][src]

Statics

+
FILES
INITIAL
NO_UTF8
TABS
\ No newline at end of file diff --git a/uu_expand/options/sidebar-items.js b/uu_expand/options/sidebar-items.js new file mode 100644 index 000000000..91e3f1b67 --- /dev/null +++ b/uu_expand/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["FILES",""],["INITIAL",""],["NO_UTF8",""],["TABS",""]]}); \ No newline at end of file diff --git a/uu_expand/options/static.FILES.html b/uu_expand/options/static.FILES.html new file mode 100644 index 000000000..2fbdf040d --- /dev/null +++ b/uu_expand/options/static.FILES.html @@ -0,0 +1,3 @@ +FILES in uu_expand::options - Rust + +

Static uu_expand::options::FILES[][src]

pub static FILES: &str
\ No newline at end of file diff --git a/uu_expand/options/static.INITIAL.html b/uu_expand/options/static.INITIAL.html new file mode 100644 index 000000000..4be3145a1 --- /dev/null +++ b/uu_expand/options/static.INITIAL.html @@ -0,0 +1,3 @@ +INITIAL in uu_expand::options - Rust + +

Static uu_expand::options::INITIAL[][src]

pub static INITIAL: &str
\ No newline at end of file diff --git a/uu_expand/options/static.NO_UTF8.html b/uu_expand/options/static.NO_UTF8.html new file mode 100644 index 000000000..8376e1a62 --- /dev/null +++ b/uu_expand/options/static.NO_UTF8.html @@ -0,0 +1,3 @@ +NO_UTF8 in uu_expand::options - Rust + +

Static uu_expand::options::NO_UTF8[][src]

pub static NO_UTF8: &str
\ No newline at end of file diff --git a/uu_expand/options/static.TABS.html b/uu_expand/options/static.TABS.html new file mode 100644 index 000000000..972f5668e --- /dev/null +++ b/uu_expand/options/static.TABS.html @@ -0,0 +1,3 @@ +TABS in uu_expand::options - Rust + +

Static uu_expand::options::TABS[][src]

pub static TABS: &str
\ No newline at end of file diff --git a/uu_expand/sidebar-items.js b/uu_expand/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_expand/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_expr/all.html b/uu_expr/all.html new file mode 100644 index 000000000..a7a56d472 --- /dev/null +++ b/uu_expr/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_expr/fn.uu_app.html b/uu_expr/fn.uu_app.html new file mode 100644 index 000000000..568db7119 --- /dev/null +++ b/uu_expr/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_expr - Rust + +

Function uu_expr::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_expr/fn.uumain.html b/uu_expr/fn.uumain.html new file mode 100644 index 000000000..673f7e2bb --- /dev/null +++ b/uu_expr/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_expr - Rust + +

Function uu_expr::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_expr/index.html b/uu_expr/index.html new file mode 100644 index 000000000..9fe03e544 --- /dev/null +++ b/uu_expr/index.html @@ -0,0 +1,4 @@ +uu_expr - Rust + +

Crate uu_expr[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_expr/sidebar-items.js b/uu_expr/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_expr/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_factor/all.html b/uu_factor/all.html new file mode 100644 index 000000000..2da4e39ca --- /dev/null +++ b/uu_factor/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Functions

Constants

\ No newline at end of file diff --git a/uu_factor/factor/fn.factor.html b/uu_factor/factor/fn.factor.html new file mode 100644 index 000000000..758e9df31 --- /dev/null +++ b/uu_factor/factor/fn.factor.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../uu_factor/fn.factor.html...

+ + + \ No newline at end of file diff --git a/uu_factor/factor/struct.Factors.html b/uu_factor/factor/struct.Factors.html new file mode 100644 index 000000000..0ef90f8a7 --- /dev/null +++ b/uu_factor/factor/struct.Factors.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../uu_factor/struct.Factors.html...

+ + + \ No newline at end of file diff --git a/uu_factor/fn.factor.html b/uu_factor/fn.factor.html new file mode 100644 index 000000000..b0010a89b --- /dev/null +++ b/uu_factor/fn.factor.html @@ -0,0 +1,3 @@ +factor in uu_factor - Rust + +

Function uu_factor::factor[][src]

pub fn factor(n: u64) -> Factors
\ No newline at end of file diff --git a/uu_factor/fn.uu_app.html b/uu_factor/fn.uu_app.html new file mode 100644 index 000000000..bfde9e2f1 --- /dev/null +++ b/uu_factor/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_factor - Rust + +

Function uu_factor::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_factor/fn.uumain.html b/uu_factor/fn.uumain.html new file mode 100644 index 000000000..a5f0a2d58 --- /dev/null +++ b/uu_factor/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_factor - Rust + +

Function uu_factor::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_factor/index.html b/uu_factor/index.html new file mode 100644 index 000000000..46daed1ec --- /dev/null +++ b/uu_factor/index.html @@ -0,0 +1,6 @@ +uu_factor - Rust + +

Crate uu_factor[][src]

Modules

+
numeric
table

Structs

+
Factors

Functions

+
factor
uu_app
uumain
\ No newline at end of file diff --git a/uu_factor/numeric/fn.gcd.html b/uu_factor/numeric/fn.gcd.html new file mode 100644 index 000000000..536ffca6d --- /dev/null +++ b/uu_factor/numeric/fn.gcd.html @@ -0,0 +1,3 @@ +gcd in uu_factor::numeric - Rust + +

Function uu_factor::numeric::gcd[][src]

pub fn gcd(u: u64, v: u64) -> u64
\ No newline at end of file diff --git a/uu_factor/numeric/gcd/fn.gcd.html b/uu_factor/numeric/gcd/fn.gcd.html new file mode 100644 index 000000000..d45cf6d22 --- /dev/null +++ b/uu_factor/numeric/gcd/fn.gcd.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uu_factor/numeric/fn.gcd.html...

+ + + \ No newline at end of file diff --git a/uu_factor/numeric/index.html b/uu_factor/numeric/index.html new file mode 100644 index 000000000..8c49e2185 --- /dev/null +++ b/uu_factor/numeric/index.html @@ -0,0 +1,4 @@ +uu_factor::numeric - Rust + +

Module uu_factor::numeric[][src]

Functions

+
gcd
\ No newline at end of file diff --git a/uu_factor/numeric/sidebar-items.js b/uu_factor/numeric/sidebar-items.js new file mode 100644 index 000000000..3fdde96f1 --- /dev/null +++ b/uu_factor/numeric/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["gcd",""]]}); \ No newline at end of file diff --git a/uu_factor/sidebar-items.js b/uu_factor/sidebar-items.js new file mode 100644 index 000000000..0787c5324 --- /dev/null +++ b/uu_factor/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["factor",""],["uu_app",""],["uumain",""]],"mod":[["numeric",""],["table",""]],"struct":[["Factors",""]]}); \ No newline at end of file diff --git a/uu_factor/struct.Factors.html b/uu_factor/struct.Factors.html new file mode 100644 index 000000000..c67918e33 --- /dev/null +++ b/uu_factor/struct.Factors.html @@ -0,0 +1,24 @@ +Factors in uu_factor - Rust + +

Struct uu_factor::Factors[][src]

pub struct Factors(_);

Implementations

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_factor/table/constant.CHUNK_SIZE.html b/uu_factor/table/constant.CHUNK_SIZE.html new file mode 100644 index 000000000..dcea1da1c --- /dev/null +++ b/uu_factor/table/constant.CHUNK_SIZE.html @@ -0,0 +1,3 @@ +CHUNK_SIZE in uu_factor::table - Rust + +

Constant uu_factor::table::CHUNK_SIZE[][src]

pub const CHUNK_SIZE: usize = 8;
\ No newline at end of file diff --git a/uu_factor/table/constant.NEXT_PRIME.html b/uu_factor/table/constant.NEXT_PRIME.html new file mode 100644 index 000000000..cf22195e9 --- /dev/null +++ b/uu_factor/table/constant.NEXT_PRIME.html @@ -0,0 +1,3 @@ +NEXT_PRIME in uu_factor::table - Rust + +

Constant uu_factor::table::NEXT_PRIME[][src]

pub const NEXT_PRIME: u64 = 2137;
\ No newline at end of file diff --git a/uu_factor/table/constant.PRIME_INVERSIONS_U64.html b/uu_factor/table/constant.PRIME_INVERSIONS_U64.html new file mode 100644 index 000000000..ea7e6d6f6 --- /dev/null +++ b/uu_factor/table/constant.PRIME_INVERSIONS_U64.html @@ -0,0 +1,3 @@ +PRIME_INVERSIONS_U64 in uu_factor::table - Rust + +

Constant uu_factor::table::PRIME_INVERSIONS_U64[][src]

pub const PRIME_INVERSIONS_U64: &[(u64, u64, u64)];
\ No newline at end of file diff --git a/uu_factor/table/fn.factor.html b/uu_factor/table/fn.factor.html new file mode 100644 index 000000000..c1afb1526 --- /dev/null +++ b/uu_factor/table/fn.factor.html @@ -0,0 +1,3 @@ +factor in uu_factor::table - Rust + +

Function uu_factor::table::factor[][src]

pub fn factor(num: &mut u64, factors: &mut Factors)
\ No newline at end of file diff --git a/uu_factor/table/fn.factor_chunk.html b/uu_factor/table/fn.factor_chunk.html new file mode 100644 index 000000000..16e6d82e1 --- /dev/null +++ b/uu_factor/table/fn.factor_chunk.html @@ -0,0 +1,3 @@ +factor_chunk in uu_factor::table - Rust + +

Function uu_factor::table::factor_chunk[][src]

pub fn factor_chunk(n_s: &mut [u64; 8], f_s: &mut [Factors; 8])
\ No newline at end of file diff --git a/uu_factor/table/index.html b/uu_factor/table/index.html new file mode 100644 index 000000000..1c3395d59 --- /dev/null +++ b/uu_factor/table/index.html @@ -0,0 +1,5 @@ +uu_factor::table - Rust + +

Module uu_factor::table[][src]

Constants

+
CHUNK_SIZE
NEXT_PRIME
PRIME_INVERSIONS_U64

Functions

+
factor
factor_chunk
\ No newline at end of file diff --git a/uu_factor/table/sidebar-items.js b/uu_factor/table/sidebar-items.js new file mode 100644 index 000000000..6aae4c331 --- /dev/null +++ b/uu_factor/table/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["CHUNK_SIZE",""],["NEXT_PRIME",""],["PRIME_INVERSIONS_U64",""]],"fn":[["factor",""],["factor_chunk",""]]}); \ No newline at end of file diff --git a/uu_false/all.html b/uu_false/all.html new file mode 100644 index 000000000..664a34471 --- /dev/null +++ b/uu_false/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_false/fn.uu_app.html b/uu_false/fn.uu_app.html new file mode 100644 index 000000000..e997a0b4a --- /dev/null +++ b/uu_false/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_false - Rust + +

Function uu_false::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_false/fn.uumain.html b/uu_false/fn.uumain.html new file mode 100644 index 000000000..3a9ff7086 --- /dev/null +++ b/uu_false/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_false - Rust + +

Function uu_false::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_false/index.html b/uu_false/index.html new file mode 100644 index 000000000..9d702e72c --- /dev/null +++ b/uu_false/index.html @@ -0,0 +1,4 @@ +uu_false - Rust + +

Crate uu_false[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_false/sidebar-items.js b/uu_false/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_false/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_fmt/all.html b/uu_fmt/all.html new file mode 100644 index 000000000..39df49972 --- /dev/null +++ b/uu_fmt/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Functions

Typedefs

\ No newline at end of file diff --git a/uu_fmt/fn.uu_app.html b/uu_fmt/fn.uu_app.html new file mode 100644 index 000000000..b4ae1856c --- /dev/null +++ b/uu_fmt/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_fmt - Rust + +

Function uu_fmt::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_fmt/fn.uumain.html b/uu_fmt/fn.uumain.html new file mode 100644 index 000000000..a278ef81d --- /dev/null +++ b/uu_fmt/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_fmt - Rust + +

Function uu_fmt::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_fmt/index.html b/uu_fmt/index.html new file mode 100644 index 000000000..0b2ab3976 --- /dev/null +++ b/uu_fmt/index.html @@ -0,0 +1,6 @@ +uu_fmt - Rust + +

Crate uu_fmt[][src]

Structs

+
FmtOptions

Functions

+
uu_app
uumain

Type Definitions

+
FileOrStdReader
\ No newline at end of file diff --git a/uu_fmt/sidebar-items.js b/uu_fmt/sidebar-items.js new file mode 100644 index 000000000..40ad9895f --- /dev/null +++ b/uu_fmt/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"struct":[["FmtOptions",""]],"type":[["FileOrStdReader",""]]}); \ No newline at end of file diff --git a/uu_fmt/struct.FmtOptions.html b/uu_fmt/struct.FmtOptions.html new file mode 100644 index 000000000..1e0cb80b9 --- /dev/null +++ b/uu_fmt/struct.FmtOptions.html @@ -0,0 +1,12 @@ +FmtOptions in uu_fmt - Rust + +

Struct uu_fmt::FmtOptions[][src]

pub struct FmtOptions { /* fields omitted */ }

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_fmt/type.FileOrStdReader.html b/uu_fmt/type.FileOrStdReader.html new file mode 100644 index 000000000..de1e344b9 --- /dev/null +++ b/uu_fmt/type.FileOrStdReader.html @@ -0,0 +1,3 @@ +FileOrStdReader in uu_fmt - Rust + +

Type Definition uu_fmt::FileOrStdReader[][src]

type FileOrStdReader = BufReader<Box<dyn Read + 'static>>;
\ No newline at end of file diff --git a/uu_fold/all.html b/uu_fold/all.html new file mode 100644 index 000000000..7188ed4d7 --- /dev/null +++ b/uu_fold/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_fold/fn.uu_app.html b/uu_fold/fn.uu_app.html new file mode 100644 index 000000000..11e8a527e --- /dev/null +++ b/uu_fold/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_fold - Rust + +

Function uu_fold::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_fold/fn.uumain.html b/uu_fold/fn.uumain.html new file mode 100644 index 000000000..d5172fb57 --- /dev/null +++ b/uu_fold/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_fold - Rust + +

Function uu_fold::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_fold/index.html b/uu_fold/index.html new file mode 100644 index 000000000..4bc614a4d --- /dev/null +++ b/uu_fold/index.html @@ -0,0 +1,4 @@ +uu_fold - Rust + +

Crate uu_fold[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_fold/sidebar-items.js b/uu_fold/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_fold/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_groups/all.html b/uu_groups/all.html new file mode 100644 index 000000000..9582b4a90 --- /dev/null +++ b/uu_groups/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_groups/fn.uu_app.html b/uu_groups/fn.uu_app.html new file mode 100644 index 000000000..bc159de9e --- /dev/null +++ b/uu_groups/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_groups - Rust + +

Function uu_groups::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_groups/fn.uumain.html b/uu_groups/fn.uumain.html new file mode 100644 index 000000000..ac6430016 --- /dev/null +++ b/uu_groups/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_groups - Rust + +

Function uu_groups::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_groups/index.html b/uu_groups/index.html new file mode 100644 index 000000000..f2da09de4 --- /dev/null +++ b/uu_groups/index.html @@ -0,0 +1,4 @@ +uu_groups - Rust + +

Crate uu_groups[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_groups/sidebar-items.js b/uu_groups/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_groups/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_hashsum/all.html b/uu_hashsum/all.html new file mode 100644 index 000000000..0087d37e8 --- /dev/null +++ b/uu_hashsum/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_hashsum/fn.uu_app_common.html b/uu_hashsum/fn.uu_app_common.html new file mode 100644 index 000000000..7f88a8f51 --- /dev/null +++ b/uu_hashsum/fn.uu_app_common.html @@ -0,0 +1,3 @@ +uu_app_common in uu_hashsum - Rust + +

Function uu_hashsum::uu_app_common[][src]

pub fn uu_app_common() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_hashsum/fn.uu_app_custom.html b/uu_hashsum/fn.uu_app_custom.html new file mode 100644 index 000000000..bcba5fd37 --- /dev/null +++ b/uu_hashsum/fn.uu_app_custom.html @@ -0,0 +1,3 @@ +uu_app_custom in uu_hashsum - Rust + +

Function uu_hashsum::uu_app_custom[][src]

pub fn uu_app_custom() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_hashsum/fn.uumain.html b/uu_hashsum/fn.uumain.html new file mode 100644 index 000000000..0fb1a8a32 --- /dev/null +++ b/uu_hashsum/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_hashsum - Rust + +

Function uu_hashsum::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_hashsum/index.html b/uu_hashsum/index.html new file mode 100644 index 000000000..4a3568103 --- /dev/null +++ b/uu_hashsum/index.html @@ -0,0 +1,4 @@ +uu_hashsum - Rust + +

Crate uu_hashsum[][src]

Functions

+
uu_app_common
uu_app_custom
uumain
\ No newline at end of file diff --git a/uu_hashsum/sidebar-items.js b/uu_hashsum/sidebar-items.js new file mode 100644 index 000000000..2aed11c4c --- /dev/null +++ b/uu_hashsum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app_common",""],["uu_app_custom",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_head/all.html b/uu_head/all.html new file mode 100644 index 000000000..bc25c1779 --- /dev/null +++ b/uu_head/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_head/fn.uu_app.html b/uu_head/fn.uu_app.html new file mode 100644 index 000000000..c3daf673f --- /dev/null +++ b/uu_head/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_head - Rust + +

Function uu_head::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_head/fn.uumain.html b/uu_head/fn.uumain.html new file mode 100644 index 000000000..41e3024b0 --- /dev/null +++ b/uu_head/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_head - Rust + +

Function uu_head::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_head/index.html b/uu_head/index.html new file mode 100644 index 000000000..deebe3ca9 --- /dev/null +++ b/uu_head/index.html @@ -0,0 +1,4 @@ +uu_head - Rust + +

Crate uu_head[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_head/sidebar-items.js b/uu_head/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_head/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_hostid/all.html b/uu_hostid/all.html new file mode 100644 index 000000000..dceb29ecf --- /dev/null +++ b/uu_hostid/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_hostid/fn.gethostid.html b/uu_hostid/fn.gethostid.html new file mode 100644 index 000000000..a00c46748 --- /dev/null +++ b/uu_hostid/fn.gethostid.html @@ -0,0 +1,3 @@ +gethostid in uu_hostid - Rust + +

Function uu_hostid::gethostid[][src]

pub unsafe extern "C" fn gethostid() -> c_long
\ No newline at end of file diff --git a/uu_hostid/fn.uu_app.html b/uu_hostid/fn.uu_app.html new file mode 100644 index 000000000..b953aaeea --- /dev/null +++ b/uu_hostid/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_hostid - Rust + +

Function uu_hostid::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_hostid/fn.uumain.html b/uu_hostid/fn.uumain.html new file mode 100644 index 000000000..7593ac159 --- /dev/null +++ b/uu_hostid/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_hostid - Rust + +

Function uu_hostid::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_hostid/index.html b/uu_hostid/index.html new file mode 100644 index 000000000..9a1a57faa --- /dev/null +++ b/uu_hostid/index.html @@ -0,0 +1,4 @@ +uu_hostid - Rust + +

Crate uu_hostid[][src]

Functions

+
gethostid
uu_app
uumain
\ No newline at end of file diff --git a/uu_hostid/sidebar-items.js b/uu_hostid/sidebar-items.js new file mode 100644 index 000000000..74f15776b --- /dev/null +++ b/uu_hostid/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["gethostid",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_hostname/all.html b/uu_hostname/all.html new file mode 100644 index 000000000..f18433b94 --- /dev/null +++ b/uu_hostname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_hostname/fn.uu_app.html b/uu_hostname/fn.uu_app.html new file mode 100644 index 000000000..62a182cc5 --- /dev/null +++ b/uu_hostname/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_hostname - Rust + +

Function uu_hostname::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_hostname/fn.uumain.html b/uu_hostname/fn.uumain.html new file mode 100644 index 000000000..ed2a7f61c --- /dev/null +++ b/uu_hostname/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_hostname - Rust + +

Function uu_hostname::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_hostname/index.html b/uu_hostname/index.html new file mode 100644 index 000000000..4e4889bbe --- /dev/null +++ b/uu_hostname/index.html @@ -0,0 +1,4 @@ +uu_hostname - Rust + +

Crate uu_hostname[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_hostname/sidebar-items.js b/uu_hostname/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_hostname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_id/all.html b/uu_id/all.html new file mode 100644 index 000000000..922be8f93 --- /dev/null +++ b/uu_id/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_id/fn.uu_app.html b/uu_id/fn.uu_app.html new file mode 100644 index 000000000..e7ea0598a --- /dev/null +++ b/uu_id/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_id - Rust + +

Function uu_id::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_id/fn.uumain.html b/uu_id/fn.uumain.html new file mode 100644 index 000000000..8bd7e1ecc --- /dev/null +++ b/uu_id/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_id - Rust + +

Function uu_id::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_id/index.html b/uu_id/index.html new file mode 100644 index 000000000..9646a981b --- /dev/null +++ b/uu_id/index.html @@ -0,0 +1,5 @@ +uu_id - Rust + +

Crate uu_id[][src]

Re-exports

+
pub use uucore::libc;

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_id/sidebar-items.js b/uu_id/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_id/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_install/all.html b/uu_install/all.html new file mode 100644 index 000000000..5eeeeaf69 --- /dev/null +++ b/uu_install/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Functions

\ No newline at end of file diff --git a/uu_install/enum.MainFunction.html b/uu_install/enum.MainFunction.html new file mode 100644 index 000000000..71568d9d4 --- /dev/null +++ b/uu_install/enum.MainFunction.html @@ -0,0 +1,28 @@ +MainFunction in uu_install - Rust + +

Enum uu_install::MainFunction[][src]

pub enum MainFunction {
+    Directory,
+    Standard,
+}

+ Variants

+
Directory

Create directories

+
Standard

Install files to locations (primary functionality)

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_install/fn.uu_app.html b/uu_install/fn.uu_app.html new file mode 100644 index 000000000..47168f5eb --- /dev/null +++ b/uu_install/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_install - Rust + +

Function uu_install::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_install/fn.uumain.html b/uu_install/fn.uumain.html new file mode 100644 index 000000000..cecfbc1b1 --- /dev/null +++ b/uu_install/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_install - Rust + +

Function uu_install::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_install/index.html b/uu_install/index.html new file mode 100644 index 000000000..c1da0f99d --- /dev/null +++ b/uu_install/index.html @@ -0,0 +1,6 @@ +uu_install - Rust + +

Crate uu_install[][src]

Structs

+
Behavior

Enums

+
MainFunction

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_install/sidebar-items.js b/uu_install/sidebar-items.js new file mode 100644 index 000000000..5fb8df705 --- /dev/null +++ b/uu_install/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["MainFunction",""]],"fn":[["uu_app",""],["uumain",""]],"struct":[["Behavior",""]]}); \ No newline at end of file diff --git a/uu_install/struct.Behavior.html b/uu_install/struct.Behavior.html new file mode 100644 index 000000000..f3eb60fe5 --- /dev/null +++ b/uu_install/struct.Behavior.html @@ -0,0 +1,13 @@ +Behavior in uu_install - Rust + +

Struct uu_install::Behavior[][src]

pub struct Behavior { /* fields omitted */ }

Implementations

Determine the mode for chmod after copy.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_join/all.html b/uu_join/all.html new file mode 100644 index 000000000..b04ceb3a8 --- /dev/null +++ b/uu_join/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_join/fn.uu_app.html b/uu_join/fn.uu_app.html new file mode 100644 index 000000000..72700e90e --- /dev/null +++ b/uu_join/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_join - Rust + +

Function uu_join::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_join/fn.uumain.html b/uu_join/fn.uumain.html new file mode 100644 index 000000000..afe01f393 --- /dev/null +++ b/uu_join/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_join - Rust + +

Function uu_join::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_join/index.html b/uu_join/index.html new file mode 100644 index 000000000..e1934766c --- /dev/null +++ b/uu_join/index.html @@ -0,0 +1,4 @@ +uu_join - Rust + +

Crate uu_join[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_join/sidebar-items.js b/uu_join/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_join/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_kill/all.html b/uu_kill/all.html new file mode 100644 index 000000000..689111e6a --- /dev/null +++ b/uu_kill/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Enums

Functions

Statics

\ No newline at end of file diff --git a/uu_kill/enum.Mode.html b/uu_kill/enum.Mode.html new file mode 100644 index 000000000..d43de7216 --- /dev/null +++ b/uu_kill/enum.Mode.html @@ -0,0 +1,24 @@ +Mode in uu_kill - Rust + +

Enum uu_kill::Mode[][src]

pub enum Mode {
+    Kill,
+    Table,
+    List,
+}

+ Variants

+
Kill
Table
List

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_kill/fn.uu_app.html b/uu_kill/fn.uu_app.html new file mode 100644 index 000000000..4a64f8ad1 --- /dev/null +++ b/uu_kill/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_kill - Rust + +

Function uu_kill::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_kill/fn.uumain.html b/uu_kill/fn.uumain.html new file mode 100644 index 000000000..8f2deb0cd --- /dev/null +++ b/uu_kill/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_kill - Rust + +

Function uu_kill::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_kill/index.html b/uu_kill/index.html new file mode 100644 index 000000000..034e1ac40 --- /dev/null +++ b/uu_kill/index.html @@ -0,0 +1,6 @@ +uu_kill - Rust + +

Crate uu_kill[][src]

Modules

+
options

Enums

+
Mode

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_kill/options/index.html b/uu_kill/options/index.html new file mode 100644 index 000000000..0a523facb --- /dev/null +++ b/uu_kill/options/index.html @@ -0,0 +1,4 @@ +uu_kill::options - Rust + +

Module uu_kill::options[][src]

Statics

+
LIST
PIDS_OR_SIGNALS
SIGNAL
TABLE
TABLE_OLD
\ No newline at end of file diff --git a/uu_kill/options/sidebar-items.js b/uu_kill/options/sidebar-items.js new file mode 100644 index 000000000..cc18172db --- /dev/null +++ b/uu_kill/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["LIST",""],["PIDS_OR_SIGNALS",""],["SIGNAL",""],["TABLE",""],["TABLE_OLD",""]]}); \ No newline at end of file diff --git a/uu_kill/options/static.LIST.html b/uu_kill/options/static.LIST.html new file mode 100644 index 000000000..ff477ce23 --- /dev/null +++ b/uu_kill/options/static.LIST.html @@ -0,0 +1,3 @@ +LIST in uu_kill::options - Rust + +

Static uu_kill::options::LIST[][src]

pub static LIST: &str
\ No newline at end of file diff --git a/uu_kill/options/static.PIDS_OR_SIGNALS.html b/uu_kill/options/static.PIDS_OR_SIGNALS.html new file mode 100644 index 000000000..d28fd0ec8 --- /dev/null +++ b/uu_kill/options/static.PIDS_OR_SIGNALS.html @@ -0,0 +1,3 @@ +PIDS_OR_SIGNALS in uu_kill::options - Rust + +

Static uu_kill::options::PIDS_OR_SIGNALS[][src]

pub static PIDS_OR_SIGNALS: &str
\ No newline at end of file diff --git a/uu_kill/options/static.SIGNAL.html b/uu_kill/options/static.SIGNAL.html new file mode 100644 index 000000000..934658c23 --- /dev/null +++ b/uu_kill/options/static.SIGNAL.html @@ -0,0 +1,3 @@ +SIGNAL in uu_kill::options - Rust + +

Static uu_kill::options::SIGNAL[][src]

pub static SIGNAL: &str
\ No newline at end of file diff --git a/uu_kill/options/static.TABLE.html b/uu_kill/options/static.TABLE.html new file mode 100644 index 000000000..9b297ef2f --- /dev/null +++ b/uu_kill/options/static.TABLE.html @@ -0,0 +1,3 @@ +TABLE in uu_kill::options - Rust + +

Static uu_kill::options::TABLE[][src]

pub static TABLE: &str
\ No newline at end of file diff --git a/uu_kill/options/static.TABLE_OLD.html b/uu_kill/options/static.TABLE_OLD.html new file mode 100644 index 000000000..7a2e027af --- /dev/null +++ b/uu_kill/options/static.TABLE_OLD.html @@ -0,0 +1,3 @@ +TABLE_OLD in uu_kill::options - Rust + +

Static uu_kill::options::TABLE_OLD[][src]

pub static TABLE_OLD: &str
\ No newline at end of file diff --git a/uu_kill/sidebar-items.js b/uu_kill/sidebar-items.js new file mode 100644 index 000000000..f3592db17 --- /dev/null +++ b/uu_kill/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["Mode",""]],"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_link/all.html b/uu_link/all.html new file mode 100644 index 000000000..aa8b24b09 --- /dev/null +++ b/uu_link/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_link/fn.normalize_error_message.html b/uu_link/fn.normalize_error_message.html new file mode 100644 index 000000000..da265b8f8 --- /dev/null +++ b/uu_link/fn.normalize_error_message.html @@ -0,0 +1,3 @@ +normalize_error_message in uu_link - Rust + +

Function uu_link::normalize_error_message[][src]

pub fn normalize_error_message(e: Error) -> String
\ No newline at end of file diff --git a/uu_link/fn.uu_app.html b/uu_link/fn.uu_app.html new file mode 100644 index 000000000..fd09417a7 --- /dev/null +++ b/uu_link/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_link - Rust + +

Function uu_link::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_link/fn.uumain.html b/uu_link/fn.uumain.html new file mode 100644 index 000000000..7b6c4dbfb --- /dev/null +++ b/uu_link/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_link - Rust + +

Function uu_link::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_link/index.html b/uu_link/index.html new file mode 100644 index 000000000..86df45738 --- /dev/null +++ b/uu_link/index.html @@ -0,0 +1,5 @@ +uu_link - Rust + +

Crate uu_link[][src]

Modules

+
options

Functions

+
normalize_error_message
uu_app
uumain
\ No newline at end of file diff --git a/uu_link/options/index.html b/uu_link/options/index.html new file mode 100644 index 000000000..0b101aaf3 --- /dev/null +++ b/uu_link/options/index.html @@ -0,0 +1,4 @@ +uu_link::options - Rust + +

Module uu_link::options[][src]

Statics

+
FILES
\ No newline at end of file diff --git a/uu_link/options/sidebar-items.js b/uu_link/options/sidebar-items.js new file mode 100644 index 000000000..aadeb063e --- /dev/null +++ b/uu_link/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["FILES",""]]}); \ No newline at end of file diff --git a/uu_link/options/static.FILES.html b/uu_link/options/static.FILES.html new file mode 100644 index 000000000..ea940b46f --- /dev/null +++ b/uu_link/options/static.FILES.html @@ -0,0 +1,3 @@ +FILES in uu_link::options - Rust + +

Static uu_link::options::FILES[][src]

pub static FILES: &str
\ No newline at end of file diff --git a/uu_link/sidebar-items.js b/uu_link/sidebar-items.js new file mode 100644 index 000000000..589136b4d --- /dev/null +++ b/uu_link/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["normalize_error_message",""],["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_ln/all.html b/uu_ln/all.html new file mode 100644 index 000000000..6ba0ce208 --- /dev/null +++ b/uu_ln/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Functions

\ No newline at end of file diff --git a/uu_ln/enum.OverwriteMode.html b/uu_ln/enum.OverwriteMode.html new file mode 100644 index 000000000..f1ec8cacd --- /dev/null +++ b/uu_ln/enum.OverwriteMode.html @@ -0,0 +1,28 @@ +OverwriteMode in uu_ln - Rust + +

Enum uu_ln::OverwriteMode[][src]

pub enum OverwriteMode {
+    NoClobber,
+    Interactive,
+    Force,
+}

+ Variants

+
NoClobber
Interactive
Force

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_ln/fn.is_symlink.html b/uu_ln/fn.is_symlink.html new file mode 100644 index 000000000..3439b757c --- /dev/null +++ b/uu_ln/fn.is_symlink.html @@ -0,0 +1,3 @@ +is_symlink in uu_ln - Rust + +

Function uu_ln::is_symlink[][src]

pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool
\ No newline at end of file diff --git a/uu_ln/fn.uu_app.html b/uu_ln/fn.uu_app.html new file mode 100644 index 000000000..8339e5e80 --- /dev/null +++ b/uu_ln/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_ln - Rust + +

Function uu_ln::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_ln/fn.uumain.html b/uu_ln/fn.uumain.html new file mode 100644 index 000000000..4bd48b917 --- /dev/null +++ b/uu_ln/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_ln - Rust + +

Function uu_ln::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_ln/index.html b/uu_ln/index.html new file mode 100644 index 000000000..d64a1b769 --- /dev/null +++ b/uu_ln/index.html @@ -0,0 +1,6 @@ +uu_ln - Rust + +

Crate uu_ln[][src]

Structs

+
Settings

Enums

+
OverwriteMode

Functions

+
is_symlink
uu_app
uumain
\ No newline at end of file diff --git a/uu_ln/sidebar-items.js b/uu_ln/sidebar-items.js new file mode 100644 index 000000000..acc4dafc8 --- /dev/null +++ b/uu_ln/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["OverwriteMode",""]],"fn":[["is_symlink",""],["uu_app",""],["uumain",""]],"struct":[["Settings",""]]}); \ No newline at end of file diff --git a/uu_ln/struct.Settings.html b/uu_ln/struct.Settings.html new file mode 100644 index 000000000..7d1595137 --- /dev/null +++ b/uu_ln/struct.Settings.html @@ -0,0 +1,12 @@ +Settings in uu_ln - Rust + +

Struct uu_ln::Settings[][src]

pub struct Settings { /* fields omitted */ }

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_logname/all.html b/uu_logname/all.html new file mode 100644 index 000000000..1100e1c2f --- /dev/null +++ b/uu_logname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_logname/fn.getlogin.html b/uu_logname/fn.getlogin.html new file mode 100644 index 000000000..af14c4e5f --- /dev/null +++ b/uu_logname/fn.getlogin.html @@ -0,0 +1,3 @@ +getlogin in uu_logname - Rust + +

Function uu_logname::getlogin[][src]

pub unsafe extern "C" fn getlogin() -> *const c_char
\ No newline at end of file diff --git a/uu_logname/fn.uu_app.html b/uu_logname/fn.uu_app.html new file mode 100644 index 000000000..d26b9bb0f --- /dev/null +++ b/uu_logname/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_logname - Rust + +

Function uu_logname::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_logname/fn.uumain.html b/uu_logname/fn.uumain.html new file mode 100644 index 000000000..98ea71761 --- /dev/null +++ b/uu_logname/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_logname - Rust + +

Function uu_logname::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_logname/index.html b/uu_logname/index.html new file mode 100644 index 000000000..299ba98b4 --- /dev/null +++ b/uu_logname/index.html @@ -0,0 +1,4 @@ +uu_logname - Rust + +

Crate uu_logname[][src]

Functions

+
getlogin
uu_app
uumain
\ No newline at end of file diff --git a/uu_logname/sidebar-items.js b/uu_logname/sidebar-items.js new file mode 100644 index 000000000..fca66c23c --- /dev/null +++ b/uu_logname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["getlogin",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_ls/all.html b/uu_ls/all.html new file mode 100644 index 000000000..00d79bb6f --- /dev/null +++ b/uu_ls/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_ls/fn.uu_app.html b/uu_ls/fn.uu_app.html new file mode 100644 index 000000000..b7ba276c9 --- /dev/null +++ b/uu_ls/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_ls - Rust + +

Function uu_ls::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_ls/fn.uumain.html b/uu_ls/fn.uumain.html new file mode 100644 index 000000000..ad10ff1b4 --- /dev/null +++ b/uu_ls/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_ls - Rust + +

Function uu_ls::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_ls/index.html b/uu_ls/index.html new file mode 100644 index 000000000..8764464d1 --- /dev/null +++ b/uu_ls/index.html @@ -0,0 +1,5 @@ +uu_ls - Rust + +

Crate uu_ls[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_ls/options/dereference/index.html b/uu_ls/options/dereference/index.html new file mode 100644 index 000000000..88a88e508 --- /dev/null +++ b/uu_ls/options/dereference/index.html @@ -0,0 +1,4 @@ +uu_ls::options::dereference - Rust + +

Module uu_ls::options::dereference[][src]

Statics

+
ALL
ARGS
DIR_ARGS
\ No newline at end of file diff --git a/uu_ls/options/dereference/sidebar-items.js b/uu_ls/options/dereference/sidebar-items.js new file mode 100644 index 000000000..0d6e7e761 --- /dev/null +++ b/uu_ls/options/dereference/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ALL",""],["ARGS",""],["DIR_ARGS",""]]}); \ No newline at end of file diff --git a/uu_ls/options/dereference/static.ALL.html b/uu_ls/options/dereference/static.ALL.html new file mode 100644 index 000000000..93bf871fe --- /dev/null +++ b/uu_ls/options/dereference/static.ALL.html @@ -0,0 +1,3 @@ +ALL in uu_ls::options::dereference - Rust + +

Static uu_ls::options::dereference::ALL[][src]

pub static ALL: &str
\ No newline at end of file diff --git a/uu_ls/options/dereference/static.ARGS.html b/uu_ls/options/dereference/static.ARGS.html new file mode 100644 index 000000000..9cd90a8d0 --- /dev/null +++ b/uu_ls/options/dereference/static.ARGS.html @@ -0,0 +1,3 @@ +ARGS in uu_ls::options::dereference - Rust + +

Static uu_ls::options::dereference::ARGS[][src]

pub static ARGS: &str
\ No newline at end of file diff --git a/uu_ls/options/dereference/static.DIR_ARGS.html b/uu_ls/options/dereference/static.DIR_ARGS.html new file mode 100644 index 000000000..3c592211c --- /dev/null +++ b/uu_ls/options/dereference/static.DIR_ARGS.html @@ -0,0 +1,3 @@ +DIR_ARGS in uu_ls::options::dereference - Rust + +

Static uu_ls::options::dereference::DIR_ARGS[][src]

pub static DIR_ARGS: &str
\ No newline at end of file diff --git a/uu_ls/options/files/index.html b/uu_ls/options/files/index.html new file mode 100644 index 000000000..fc8ffd7da --- /dev/null +++ b/uu_ls/options/files/index.html @@ -0,0 +1,4 @@ +uu_ls::options::files - Rust + +

Module uu_ls::options::files[][src]

Statics

+
ALL
ALMOST_ALL
\ No newline at end of file diff --git a/uu_ls/options/files/sidebar-items.js b/uu_ls/options/files/sidebar-items.js new file mode 100644 index 000000000..bdc8a28ce --- /dev/null +++ b/uu_ls/options/files/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ALL",""],["ALMOST_ALL",""]]}); \ No newline at end of file diff --git a/uu_ls/options/files/static.ALL.html b/uu_ls/options/files/static.ALL.html new file mode 100644 index 000000000..5981c97b0 --- /dev/null +++ b/uu_ls/options/files/static.ALL.html @@ -0,0 +1,3 @@ +ALL in uu_ls::options::files - Rust + +

Static uu_ls::options::files::ALL[][src]

pub static ALL: &str
\ No newline at end of file diff --git a/uu_ls/options/files/static.ALMOST_ALL.html b/uu_ls/options/files/static.ALMOST_ALL.html new file mode 100644 index 000000000..4b314f77a --- /dev/null +++ b/uu_ls/options/files/static.ALMOST_ALL.html @@ -0,0 +1,3 @@ +ALMOST_ALL in uu_ls::options::files - Rust + +

Static uu_ls::options::files::ALMOST_ALL[][src]

pub static ALMOST_ALL: &str
\ No newline at end of file diff --git a/uu_ls/options/format/index.html b/uu_ls/options/format/index.html new file mode 100644 index 000000000..1b8bf4823 --- /dev/null +++ b/uu_ls/options/format/index.html @@ -0,0 +1,4 @@ +uu_ls::options::format - Rust + +

Module uu_ls::options::format[][src]

Statics

+
ACROSS
COLUMNS
COMMAS
LONG
LONG_NO_GROUP
LONG_NO_OWNER
LONG_NUMERIC_UID_GID
ONE_LINE
\ No newline at end of file diff --git a/uu_ls/options/format/sidebar-items.js b/uu_ls/options/format/sidebar-items.js new file mode 100644 index 000000000..5de714568 --- /dev/null +++ b/uu_ls/options/format/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ACROSS",""],["COLUMNS",""],["COMMAS",""],["LONG",""],["LONG_NO_GROUP",""],["LONG_NO_OWNER",""],["LONG_NUMERIC_UID_GID",""],["ONE_LINE",""]]}); \ No newline at end of file diff --git a/uu_ls/options/format/static.ACROSS.html b/uu_ls/options/format/static.ACROSS.html new file mode 100644 index 000000000..ca6f09d85 --- /dev/null +++ b/uu_ls/options/format/static.ACROSS.html @@ -0,0 +1,3 @@ +ACROSS in uu_ls::options::format - Rust + +

Static uu_ls::options::format::ACROSS[][src]

pub static ACROSS: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.COLUMNS.html b/uu_ls/options/format/static.COLUMNS.html new file mode 100644 index 000000000..bdd1f1d4a --- /dev/null +++ b/uu_ls/options/format/static.COLUMNS.html @@ -0,0 +1,3 @@ +COLUMNS in uu_ls::options::format - Rust + +

Static uu_ls::options::format::COLUMNS[][src]

pub static COLUMNS: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.COMMAS.html b/uu_ls/options/format/static.COMMAS.html new file mode 100644 index 000000000..d217fc0b6 --- /dev/null +++ b/uu_ls/options/format/static.COMMAS.html @@ -0,0 +1,3 @@ +COMMAS in uu_ls::options::format - Rust + +

Static uu_ls::options::format::COMMAS[][src]

pub static COMMAS: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.LONG.html b/uu_ls/options/format/static.LONG.html new file mode 100644 index 000000000..f9b92f3fa --- /dev/null +++ b/uu_ls/options/format/static.LONG.html @@ -0,0 +1,3 @@ +LONG in uu_ls::options::format - Rust + +

Static uu_ls::options::format::LONG[][src]

pub static LONG: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.LONG_NO_GROUP.html b/uu_ls/options/format/static.LONG_NO_GROUP.html new file mode 100644 index 000000000..dc8ece767 --- /dev/null +++ b/uu_ls/options/format/static.LONG_NO_GROUP.html @@ -0,0 +1,3 @@ +LONG_NO_GROUP in uu_ls::options::format - Rust + +

Static uu_ls::options::format::LONG_NO_GROUP[][src]

pub static LONG_NO_GROUP: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.LONG_NO_OWNER.html b/uu_ls/options/format/static.LONG_NO_OWNER.html new file mode 100644 index 000000000..547cb39a9 --- /dev/null +++ b/uu_ls/options/format/static.LONG_NO_OWNER.html @@ -0,0 +1,3 @@ +LONG_NO_OWNER in uu_ls::options::format - Rust + +

Static uu_ls::options::format::LONG_NO_OWNER[][src]

pub static LONG_NO_OWNER: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.LONG_NUMERIC_UID_GID.html b/uu_ls/options/format/static.LONG_NUMERIC_UID_GID.html new file mode 100644 index 000000000..61d1ace33 --- /dev/null +++ b/uu_ls/options/format/static.LONG_NUMERIC_UID_GID.html @@ -0,0 +1,3 @@ +LONG_NUMERIC_UID_GID in uu_ls::options::format - Rust + +

Static uu_ls::options::format::LONG_NUMERIC_UID_GID[][src]

pub static LONG_NUMERIC_UID_GID: &str
\ No newline at end of file diff --git a/uu_ls/options/format/static.ONE_LINE.html b/uu_ls/options/format/static.ONE_LINE.html new file mode 100644 index 000000000..bb0563ad1 --- /dev/null +++ b/uu_ls/options/format/static.ONE_LINE.html @@ -0,0 +1,3 @@ +ONE_LINE in uu_ls::options::format - Rust + +

Static uu_ls::options::format::ONE_LINE[][src]

pub static ONE_LINE: &str
\ No newline at end of file diff --git a/uu_ls/options/index.html b/uu_ls/options/index.html new file mode 100644 index 000000000..31636699c --- /dev/null +++ b/uu_ls/options/index.html @@ -0,0 +1,5 @@ +uu_ls::options - Rust + +

Module uu_ls::options[][src]

Modules

+
dereference
files
format
indicator_style
quoting
size
sort
time

Statics

+
AUTHOR
COLOR
DIRECTORY
FORMAT
FULL_TIME
HIDE
HIDE_CONTROL_CHARS
IGNORE
IGNORE_BACKUPS
INDICATOR_STYLE
INODE
NO_GROUP
PATHS
QUOTING_STYLE
RECURSIVE
REVERSE
SHOW_CONTROL_CHARS
SORT
TIME
TIME_STYLE
WIDTH
\ No newline at end of file diff --git a/uu_ls/options/indicator_style/index.html b/uu_ls/options/indicator_style/index.html new file mode 100644 index 000000000..e40f216fc --- /dev/null +++ b/uu_ls/options/indicator_style/index.html @@ -0,0 +1,4 @@ +uu_ls::options::indicator_style - Rust + +

Module uu_ls::options::indicator_style[][src]

Statics

+
CLASSIFY
FILE_TYPE
SLASH
\ No newline at end of file diff --git a/uu_ls/options/indicator_style/sidebar-items.js b/uu_ls/options/indicator_style/sidebar-items.js new file mode 100644 index 000000000..9fe7f9d1b --- /dev/null +++ b/uu_ls/options/indicator_style/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["CLASSIFY",""],["FILE_TYPE",""],["SLASH",""]]}); \ No newline at end of file diff --git a/uu_ls/options/indicator_style/static.CLASSIFY.html b/uu_ls/options/indicator_style/static.CLASSIFY.html new file mode 100644 index 000000000..26931ef2c --- /dev/null +++ b/uu_ls/options/indicator_style/static.CLASSIFY.html @@ -0,0 +1,3 @@ +CLASSIFY in uu_ls::options::indicator_style - Rust + +

Static uu_ls::options::indicator_style::CLASSIFY[][src]

pub static CLASSIFY: &str
\ No newline at end of file diff --git a/uu_ls/options/indicator_style/static.FILE_TYPE.html b/uu_ls/options/indicator_style/static.FILE_TYPE.html new file mode 100644 index 000000000..fe058942a --- /dev/null +++ b/uu_ls/options/indicator_style/static.FILE_TYPE.html @@ -0,0 +1,3 @@ +FILE_TYPE in uu_ls::options::indicator_style - Rust + +

Static uu_ls::options::indicator_style::FILE_TYPE[][src]

pub static FILE_TYPE: &str
\ No newline at end of file diff --git a/uu_ls/options/indicator_style/static.SLASH.html b/uu_ls/options/indicator_style/static.SLASH.html new file mode 100644 index 000000000..36276d7bc --- /dev/null +++ b/uu_ls/options/indicator_style/static.SLASH.html @@ -0,0 +1,3 @@ +SLASH in uu_ls::options::indicator_style - Rust + +

Static uu_ls::options::indicator_style::SLASH[][src]

pub static SLASH: &str
\ No newline at end of file diff --git a/uu_ls/options/quoting/index.html b/uu_ls/options/quoting/index.html new file mode 100644 index 000000000..8819455c7 --- /dev/null +++ b/uu_ls/options/quoting/index.html @@ -0,0 +1,4 @@ +uu_ls::options::quoting - Rust + +

Module uu_ls::options::quoting[][src]

Statics

+
C
ESCAPE
LITERAL
\ No newline at end of file diff --git a/uu_ls/options/quoting/sidebar-items.js b/uu_ls/options/quoting/sidebar-items.js new file mode 100644 index 000000000..bf3fa2b3f --- /dev/null +++ b/uu_ls/options/quoting/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["C",""],["ESCAPE",""],["LITERAL",""]]}); \ No newline at end of file diff --git a/uu_ls/options/quoting/static.C.html b/uu_ls/options/quoting/static.C.html new file mode 100644 index 000000000..5e26ab6f7 --- /dev/null +++ b/uu_ls/options/quoting/static.C.html @@ -0,0 +1,3 @@ +C in uu_ls::options::quoting - Rust + +

Static uu_ls::options::quoting::C[][src]

pub static C: &str
\ No newline at end of file diff --git a/uu_ls/options/quoting/static.ESCAPE.html b/uu_ls/options/quoting/static.ESCAPE.html new file mode 100644 index 000000000..4044b9764 --- /dev/null +++ b/uu_ls/options/quoting/static.ESCAPE.html @@ -0,0 +1,3 @@ +ESCAPE in uu_ls::options::quoting - Rust + +

Static uu_ls::options::quoting::ESCAPE[][src]

pub static ESCAPE: &str
\ No newline at end of file diff --git a/uu_ls/options/quoting/static.LITERAL.html b/uu_ls/options/quoting/static.LITERAL.html new file mode 100644 index 000000000..a34e0f1f2 --- /dev/null +++ b/uu_ls/options/quoting/static.LITERAL.html @@ -0,0 +1,3 @@ +LITERAL in uu_ls::options::quoting - Rust + +

Static uu_ls::options::quoting::LITERAL[][src]

pub static LITERAL: &str
\ No newline at end of file diff --git a/uu_ls/options/sidebar-items.js b/uu_ls/options/sidebar-items.js new file mode 100644 index 000000000..36d7118d4 --- /dev/null +++ b/uu_ls/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["dereference",""],["files",""],["format",""],["indicator_style",""],["quoting",""],["size",""],["sort",""],["time",""]],"static":[["AUTHOR",""],["COLOR",""],["DIRECTORY",""],["FORMAT",""],["FULL_TIME",""],["HIDE",""],["HIDE_CONTROL_CHARS",""],["IGNORE",""],["IGNORE_BACKUPS",""],["INDICATOR_STYLE",""],["INODE",""],["NO_GROUP",""],["PATHS",""],["QUOTING_STYLE",""],["RECURSIVE",""],["REVERSE",""],["SHOW_CONTROL_CHARS",""],["SORT",""],["TIME",""],["TIME_STYLE",""],["WIDTH",""]]}); \ No newline at end of file diff --git a/uu_ls/options/size/index.html b/uu_ls/options/size/index.html new file mode 100644 index 000000000..94e570e1e --- /dev/null +++ b/uu_ls/options/size/index.html @@ -0,0 +1,4 @@ +uu_ls::options::size - Rust + +

Module uu_ls::options::size[][src]

Statics

+
HUMAN_READABLE
SI
\ No newline at end of file diff --git a/uu_ls/options/size/sidebar-items.js b/uu_ls/options/size/sidebar-items.js new file mode 100644 index 000000000..2dc3125c5 --- /dev/null +++ b/uu_ls/options/size/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["HUMAN_READABLE",""],["SI",""]]}); \ No newline at end of file diff --git a/uu_ls/options/size/static.HUMAN_READABLE.html b/uu_ls/options/size/static.HUMAN_READABLE.html new file mode 100644 index 000000000..dd10cf495 --- /dev/null +++ b/uu_ls/options/size/static.HUMAN_READABLE.html @@ -0,0 +1,3 @@ +HUMAN_READABLE in uu_ls::options::size - Rust + +

Static uu_ls::options::size::HUMAN_READABLE[][src]

pub static HUMAN_READABLE: &str
\ No newline at end of file diff --git a/uu_ls/options/size/static.SI.html b/uu_ls/options/size/static.SI.html new file mode 100644 index 000000000..a3ed6fa11 --- /dev/null +++ b/uu_ls/options/size/static.SI.html @@ -0,0 +1,3 @@ +SI in uu_ls::options::size - Rust + +

Static uu_ls::options::size::SI[][src]

pub static SI: &str
\ No newline at end of file diff --git a/uu_ls/options/sort/index.html b/uu_ls/options/sort/index.html new file mode 100644 index 000000000..829caf6a8 --- /dev/null +++ b/uu_ls/options/sort/index.html @@ -0,0 +1,4 @@ +uu_ls::options::sort - Rust + +

Module uu_ls::options::sort[][src]

Statics

+
EXTENSION
NONE
SIZE
TIME
VERSION
\ No newline at end of file diff --git a/uu_ls/options/sort/sidebar-items.js b/uu_ls/options/sort/sidebar-items.js new file mode 100644 index 000000000..47107ab81 --- /dev/null +++ b/uu_ls/options/sort/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["EXTENSION",""],["NONE",""],["SIZE",""],["TIME",""],["VERSION",""]]}); \ No newline at end of file diff --git a/uu_ls/options/sort/static.EXTENSION.html b/uu_ls/options/sort/static.EXTENSION.html new file mode 100644 index 000000000..1dc28bbff --- /dev/null +++ b/uu_ls/options/sort/static.EXTENSION.html @@ -0,0 +1,3 @@ +EXTENSION in uu_ls::options::sort - Rust + +

Static uu_ls::options::sort::EXTENSION[][src]

pub static EXTENSION: &str
\ No newline at end of file diff --git a/uu_ls/options/sort/static.NONE.html b/uu_ls/options/sort/static.NONE.html new file mode 100644 index 000000000..09b9928cf --- /dev/null +++ b/uu_ls/options/sort/static.NONE.html @@ -0,0 +1,3 @@ +NONE in uu_ls::options::sort - Rust + +

Static uu_ls::options::sort::NONE[][src]

pub static NONE: &str
\ No newline at end of file diff --git a/uu_ls/options/sort/static.SIZE.html b/uu_ls/options/sort/static.SIZE.html new file mode 100644 index 000000000..e8b2dbb76 --- /dev/null +++ b/uu_ls/options/sort/static.SIZE.html @@ -0,0 +1,3 @@ +SIZE in uu_ls::options::sort - Rust + +

Static uu_ls::options::sort::SIZE[][src]

pub static SIZE: &str
\ No newline at end of file diff --git a/uu_ls/options/sort/static.TIME.html b/uu_ls/options/sort/static.TIME.html new file mode 100644 index 000000000..1f85c987f --- /dev/null +++ b/uu_ls/options/sort/static.TIME.html @@ -0,0 +1,3 @@ +TIME in uu_ls::options::sort - Rust + +

Static uu_ls::options::sort::TIME[][src]

pub static TIME: &str
\ No newline at end of file diff --git a/uu_ls/options/sort/static.VERSION.html b/uu_ls/options/sort/static.VERSION.html new file mode 100644 index 000000000..9c6142f7c --- /dev/null +++ b/uu_ls/options/sort/static.VERSION.html @@ -0,0 +1,3 @@ +VERSION in uu_ls::options::sort - Rust + +

Static uu_ls::options::sort::VERSION[][src]

pub static VERSION: &str
\ No newline at end of file diff --git a/uu_ls/options/static.AUTHOR.html b/uu_ls/options/static.AUTHOR.html new file mode 100644 index 000000000..346f8dce9 --- /dev/null +++ b/uu_ls/options/static.AUTHOR.html @@ -0,0 +1,3 @@ +AUTHOR in uu_ls::options - Rust + +

Static uu_ls::options::AUTHOR[][src]

pub static AUTHOR: &str
\ No newline at end of file diff --git a/uu_ls/options/static.COLOR.html b/uu_ls/options/static.COLOR.html new file mode 100644 index 000000000..a908be9a4 --- /dev/null +++ b/uu_ls/options/static.COLOR.html @@ -0,0 +1,3 @@ +COLOR in uu_ls::options - Rust + +

Static uu_ls::options::COLOR[][src]

pub static COLOR: &str
\ No newline at end of file diff --git a/uu_ls/options/static.DIRECTORY.html b/uu_ls/options/static.DIRECTORY.html new file mode 100644 index 000000000..994e5ebb6 --- /dev/null +++ b/uu_ls/options/static.DIRECTORY.html @@ -0,0 +1,3 @@ +DIRECTORY in uu_ls::options - Rust + +

Static uu_ls::options::DIRECTORY[][src]

pub static DIRECTORY: &str
\ No newline at end of file diff --git a/uu_ls/options/static.FORMAT.html b/uu_ls/options/static.FORMAT.html new file mode 100644 index 000000000..ae8d603f3 --- /dev/null +++ b/uu_ls/options/static.FORMAT.html @@ -0,0 +1,3 @@ +FORMAT in uu_ls::options - Rust + +

Static uu_ls::options::FORMAT[][src]

pub static FORMAT: &str
\ No newline at end of file diff --git a/uu_ls/options/static.FULL_TIME.html b/uu_ls/options/static.FULL_TIME.html new file mode 100644 index 000000000..6b826eeda --- /dev/null +++ b/uu_ls/options/static.FULL_TIME.html @@ -0,0 +1,3 @@ +FULL_TIME in uu_ls::options - Rust + +

Static uu_ls::options::FULL_TIME[][src]

pub static FULL_TIME: &str
\ No newline at end of file diff --git a/uu_ls/options/static.HIDE.html b/uu_ls/options/static.HIDE.html new file mode 100644 index 000000000..35011be2a --- /dev/null +++ b/uu_ls/options/static.HIDE.html @@ -0,0 +1,3 @@ +HIDE in uu_ls::options - Rust + +

Static uu_ls::options::HIDE[][src]

pub static HIDE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.HIDE_CONTROL_CHARS.html b/uu_ls/options/static.HIDE_CONTROL_CHARS.html new file mode 100644 index 000000000..a200a0283 --- /dev/null +++ b/uu_ls/options/static.HIDE_CONTROL_CHARS.html @@ -0,0 +1,3 @@ +HIDE_CONTROL_CHARS in uu_ls::options - Rust + +

Static uu_ls::options::HIDE_CONTROL_CHARS[][src]

pub static HIDE_CONTROL_CHARS: &str
\ No newline at end of file diff --git a/uu_ls/options/static.IGNORE.html b/uu_ls/options/static.IGNORE.html new file mode 100644 index 000000000..f776b3bd5 --- /dev/null +++ b/uu_ls/options/static.IGNORE.html @@ -0,0 +1,3 @@ +IGNORE in uu_ls::options - Rust + +

Static uu_ls::options::IGNORE[][src]

pub static IGNORE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.IGNORE_BACKUPS.html b/uu_ls/options/static.IGNORE_BACKUPS.html new file mode 100644 index 000000000..0ecf35492 --- /dev/null +++ b/uu_ls/options/static.IGNORE_BACKUPS.html @@ -0,0 +1,3 @@ +IGNORE_BACKUPS in uu_ls::options - Rust + +

Static uu_ls::options::IGNORE_BACKUPS[][src]

pub static IGNORE_BACKUPS: &str
\ No newline at end of file diff --git a/uu_ls/options/static.INDICATOR_STYLE.html b/uu_ls/options/static.INDICATOR_STYLE.html new file mode 100644 index 000000000..b2e67c9d1 --- /dev/null +++ b/uu_ls/options/static.INDICATOR_STYLE.html @@ -0,0 +1,3 @@ +INDICATOR_STYLE in uu_ls::options - Rust + +

Static uu_ls::options::INDICATOR_STYLE[][src]

pub static INDICATOR_STYLE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.INODE.html b/uu_ls/options/static.INODE.html new file mode 100644 index 000000000..4cf30b4e7 --- /dev/null +++ b/uu_ls/options/static.INODE.html @@ -0,0 +1,3 @@ +INODE in uu_ls::options - Rust + +

Static uu_ls::options::INODE[][src]

pub static INODE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.NO_GROUP.html b/uu_ls/options/static.NO_GROUP.html new file mode 100644 index 000000000..e1f31757c --- /dev/null +++ b/uu_ls/options/static.NO_GROUP.html @@ -0,0 +1,3 @@ +NO_GROUP in uu_ls::options - Rust + +

Static uu_ls::options::NO_GROUP[][src]

pub static NO_GROUP: &str
\ No newline at end of file diff --git a/uu_ls/options/static.PATHS.html b/uu_ls/options/static.PATHS.html new file mode 100644 index 000000000..5eb8a8ab3 --- /dev/null +++ b/uu_ls/options/static.PATHS.html @@ -0,0 +1,3 @@ +PATHS in uu_ls::options - Rust + +

Static uu_ls::options::PATHS[][src]

pub static PATHS: &str
\ No newline at end of file diff --git a/uu_ls/options/static.QUOTING_STYLE.html b/uu_ls/options/static.QUOTING_STYLE.html new file mode 100644 index 000000000..094333ea0 --- /dev/null +++ b/uu_ls/options/static.QUOTING_STYLE.html @@ -0,0 +1,3 @@ +QUOTING_STYLE in uu_ls::options - Rust + +

Static uu_ls::options::QUOTING_STYLE[][src]

pub static QUOTING_STYLE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.RECURSIVE.html b/uu_ls/options/static.RECURSIVE.html new file mode 100644 index 000000000..965b9f86a --- /dev/null +++ b/uu_ls/options/static.RECURSIVE.html @@ -0,0 +1,3 @@ +RECURSIVE in uu_ls::options - Rust + +

Static uu_ls::options::RECURSIVE[][src]

pub static RECURSIVE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.REVERSE.html b/uu_ls/options/static.REVERSE.html new file mode 100644 index 000000000..ba11cd17a --- /dev/null +++ b/uu_ls/options/static.REVERSE.html @@ -0,0 +1,3 @@ +REVERSE in uu_ls::options - Rust + +

Static uu_ls::options::REVERSE[][src]

pub static REVERSE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.SHOW_CONTROL_CHARS.html b/uu_ls/options/static.SHOW_CONTROL_CHARS.html new file mode 100644 index 000000000..96ccee4e7 --- /dev/null +++ b/uu_ls/options/static.SHOW_CONTROL_CHARS.html @@ -0,0 +1,3 @@ +SHOW_CONTROL_CHARS in uu_ls::options - Rust + +

Static uu_ls::options::SHOW_CONTROL_CHARS[][src]

pub static SHOW_CONTROL_CHARS: &str
\ No newline at end of file diff --git a/uu_ls/options/static.SORT.html b/uu_ls/options/static.SORT.html new file mode 100644 index 000000000..bf6f34929 --- /dev/null +++ b/uu_ls/options/static.SORT.html @@ -0,0 +1,3 @@ +SORT in uu_ls::options - Rust + +

Static uu_ls::options::SORT[][src]

pub static SORT: &str
\ No newline at end of file diff --git a/uu_ls/options/static.TIME.html b/uu_ls/options/static.TIME.html new file mode 100644 index 000000000..f9054da6f --- /dev/null +++ b/uu_ls/options/static.TIME.html @@ -0,0 +1,3 @@ +TIME in uu_ls::options - Rust + +

Static uu_ls::options::TIME[][src]

pub static TIME: &str
\ No newline at end of file diff --git a/uu_ls/options/static.TIME_STYLE.html b/uu_ls/options/static.TIME_STYLE.html new file mode 100644 index 000000000..f883f0a3e --- /dev/null +++ b/uu_ls/options/static.TIME_STYLE.html @@ -0,0 +1,3 @@ +TIME_STYLE in uu_ls::options - Rust + +

Static uu_ls::options::TIME_STYLE[][src]

pub static TIME_STYLE: &str
\ No newline at end of file diff --git a/uu_ls/options/static.WIDTH.html b/uu_ls/options/static.WIDTH.html new file mode 100644 index 000000000..b1c1c67b5 --- /dev/null +++ b/uu_ls/options/static.WIDTH.html @@ -0,0 +1,3 @@ +WIDTH in uu_ls::options - Rust + +

Static uu_ls::options::WIDTH[][src]

pub static WIDTH: &str
\ No newline at end of file diff --git a/uu_ls/options/time/index.html b/uu_ls/options/time/index.html new file mode 100644 index 000000000..77a9cb2a8 --- /dev/null +++ b/uu_ls/options/time/index.html @@ -0,0 +1,4 @@ +uu_ls::options::time - Rust + +

Module uu_ls::options::time[][src]

Statics

+
ACCESS
CHANGE
\ No newline at end of file diff --git a/uu_ls/options/time/sidebar-items.js b/uu_ls/options/time/sidebar-items.js new file mode 100644 index 000000000..90bddbe35 --- /dev/null +++ b/uu_ls/options/time/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ACCESS",""],["CHANGE",""]]}); \ No newline at end of file diff --git a/uu_ls/options/time/static.ACCESS.html b/uu_ls/options/time/static.ACCESS.html new file mode 100644 index 000000000..92d6c77d0 --- /dev/null +++ b/uu_ls/options/time/static.ACCESS.html @@ -0,0 +1,3 @@ +ACCESS in uu_ls::options::time - Rust + +

Static uu_ls::options::time::ACCESS[][src]

pub static ACCESS: &str
\ No newline at end of file diff --git a/uu_ls/options/time/static.CHANGE.html b/uu_ls/options/time/static.CHANGE.html new file mode 100644 index 000000000..3331f94de --- /dev/null +++ b/uu_ls/options/time/static.CHANGE.html @@ -0,0 +1,3 @@ +CHANGE in uu_ls::options::time - Rust + +

Static uu_ls::options::time::CHANGE[][src]

pub static CHANGE: &str
\ No newline at end of file diff --git a/uu_ls/sidebar-items.js b/uu_ls/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_ls/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_mkdir/all.html b/uu_mkdir/all.html new file mode 100644 index 000000000..7929676c3 --- /dev/null +++ b/uu_mkdir/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_mkdir/fn.uu_app.html b/uu_mkdir/fn.uu_app.html new file mode 100644 index 000000000..e66b2028b --- /dev/null +++ b/uu_mkdir/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_mkdir - Rust + +

Function uu_mkdir::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_mkdir/fn.uumain.html b/uu_mkdir/fn.uumain.html new file mode 100644 index 000000000..8122263a6 --- /dev/null +++ b/uu_mkdir/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_mkdir - Rust + +

Function uu_mkdir::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_mkdir/index.html b/uu_mkdir/index.html new file mode 100644 index 000000000..d55146fc4 --- /dev/null +++ b/uu_mkdir/index.html @@ -0,0 +1,4 @@ +uu_mkdir - Rust + +

Crate uu_mkdir[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_mkdir/sidebar-items.js b/uu_mkdir/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_mkdir/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_mkfifo/all.html b/uu_mkfifo/all.html new file mode 100644 index 000000000..05cc0350e --- /dev/null +++ b/uu_mkfifo/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_mkfifo/fn.uu_app.html b/uu_mkfifo/fn.uu_app.html new file mode 100644 index 000000000..c502d8b26 --- /dev/null +++ b/uu_mkfifo/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_mkfifo - Rust + +

Function uu_mkfifo::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_mkfifo/fn.uumain.html b/uu_mkfifo/fn.uumain.html new file mode 100644 index 000000000..c43b4e432 --- /dev/null +++ b/uu_mkfifo/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_mkfifo - Rust + +

Function uu_mkfifo::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_mkfifo/index.html b/uu_mkfifo/index.html new file mode 100644 index 000000000..b6e87b133 --- /dev/null +++ b/uu_mkfifo/index.html @@ -0,0 +1,4 @@ +uu_mkfifo - Rust + +

Crate uu_mkfifo[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_mkfifo/sidebar-items.js b/uu_mkfifo/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_mkfifo/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_mknod/all.html b/uu_mknod/all.html new file mode 100644 index 000000000..62b489c0c --- /dev/null +++ b/uu_mknod/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_mknod/fn.uu_app.html b/uu_mknod/fn.uu_app.html new file mode 100644 index 000000000..5dfc78c05 --- /dev/null +++ b/uu_mknod/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_mknod - Rust + +

Function uu_mknod::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_mknod/fn.uumain.html b/uu_mknod/fn.uumain.html new file mode 100644 index 000000000..b3a3dfccc --- /dev/null +++ b/uu_mknod/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_mknod - Rust + +

Function uu_mknod::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_mknod/index.html b/uu_mknod/index.html new file mode 100644 index 000000000..cafc1a708 --- /dev/null +++ b/uu_mknod/index.html @@ -0,0 +1,4 @@ +uu_mknod - Rust + +

Crate uu_mknod[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_mknod/sidebar-items.js b/uu_mknod/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_mknod/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_mktemp/all.html b/uu_mktemp/all.html new file mode 100644 index 000000000..6c7d15f9e --- /dev/null +++ b/uu_mktemp/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_mktemp/fn.dry_exec.html b/uu_mktemp/fn.dry_exec.html new file mode 100644 index 000000000..f500963ad --- /dev/null +++ b/uu_mktemp/fn.dry_exec.html @@ -0,0 +1,3 @@ +dry_exec in uu_mktemp - Rust + +

Function uu_mktemp::dry_exec[][src]

pub fn dry_exec(
    tmpdir: PathBuf,
    prefix: &str,
    rand: usize,
    suffix: &str
) -> UResult<()>
\ No newline at end of file diff --git a/uu_mktemp/fn.uu_app.html b/uu_mktemp/fn.uu_app.html new file mode 100644 index 000000000..f27f5fcb6 --- /dev/null +++ b/uu_mktemp/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_mktemp - Rust + +

Function uu_mktemp::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_mktemp/fn.uumain.html b/uu_mktemp/fn.uumain.html new file mode 100644 index 000000000..328761735 --- /dev/null +++ b/uu_mktemp/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_mktemp - Rust + +

Function uu_mktemp::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_mktemp/index.html b/uu_mktemp/index.html new file mode 100644 index 000000000..514436173 --- /dev/null +++ b/uu_mktemp/index.html @@ -0,0 +1,4 @@ +uu_mktemp - Rust + +

Crate uu_mktemp[][src]

Functions

+
dry_exec
uu_app
uumain
\ No newline at end of file diff --git a/uu_mktemp/sidebar-items.js b/uu_mktemp/sidebar-items.js new file mode 100644 index 000000000..6113cf509 --- /dev/null +++ b/uu_mktemp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["dry_exec",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_more/all.html b/uu_more/all.html new file mode 100644 index 000000000..a65e7f9d3 --- /dev/null +++ b/uu_more/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Constants

\ No newline at end of file diff --git a/uu_more/fn.uu_app.html b/uu_more/fn.uu_app.html new file mode 100644 index 000000000..8fb6c834e --- /dev/null +++ b/uu_more/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_more - Rust + +

Function uu_more::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_more/fn.uumain.html b/uu_more/fn.uumain.html new file mode 100644 index 000000000..764c60242 --- /dev/null +++ b/uu_more/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_more - Rust + +

Function uu_more::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_more/index.html b/uu_more/index.html new file mode 100644 index 000000000..d8f5dc6d3 --- /dev/null +++ b/uu_more/index.html @@ -0,0 +1,5 @@ +uu_more - Rust + +

Crate uu_more[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_more/options/constant.CLEAN_PRINT.html b/uu_more/options/constant.CLEAN_PRINT.html new file mode 100644 index 000000000..5bbe3570a --- /dev/null +++ b/uu_more/options/constant.CLEAN_PRINT.html @@ -0,0 +1,3 @@ +CLEAN_PRINT in uu_more::options - Rust + +

Constant uu_more::options::CLEAN_PRINT[][src]

pub const CLEAN_PRINT: &str = "clean-print";
\ No newline at end of file diff --git a/uu_more/options/constant.FILES.html b/uu_more/options/constant.FILES.html new file mode 100644 index 000000000..f48392a84 --- /dev/null +++ b/uu_more/options/constant.FILES.html @@ -0,0 +1,3 @@ +FILES in uu_more::options - Rust + +

Constant uu_more::options::FILES[][src]

pub const FILES: &str = "files";
\ No newline at end of file diff --git a/uu_more/options/constant.FROM_LINE.html b/uu_more/options/constant.FROM_LINE.html new file mode 100644 index 000000000..5edcdaf2a --- /dev/null +++ b/uu_more/options/constant.FROM_LINE.html @@ -0,0 +1,3 @@ +FROM_LINE in uu_more::options - Rust + +

Constant uu_more::options::FROM_LINE[][src]

pub const FROM_LINE: &str = "from-line";
\ No newline at end of file diff --git a/uu_more/options/constant.LINES.html b/uu_more/options/constant.LINES.html new file mode 100644 index 000000000..6f3c777e0 --- /dev/null +++ b/uu_more/options/constant.LINES.html @@ -0,0 +1,3 @@ +LINES in uu_more::options - Rust + +

Constant uu_more::options::LINES[][src]

pub const LINES: &str = "lines";
\ No newline at end of file diff --git a/uu_more/options/constant.LOGICAL.html b/uu_more/options/constant.LOGICAL.html new file mode 100644 index 000000000..337ed5b12 --- /dev/null +++ b/uu_more/options/constant.LOGICAL.html @@ -0,0 +1,3 @@ +LOGICAL in uu_more::options - Rust + +

Constant uu_more::options::LOGICAL[][src]

pub const LOGICAL: &str = "logical";
\ No newline at end of file diff --git a/uu_more/options/constant.NO_PAUSE.html b/uu_more/options/constant.NO_PAUSE.html new file mode 100644 index 000000000..01195daa6 --- /dev/null +++ b/uu_more/options/constant.NO_PAUSE.html @@ -0,0 +1,3 @@ +NO_PAUSE in uu_more::options - Rust + +

Constant uu_more::options::NO_PAUSE[][src]

pub const NO_PAUSE: &str = "no-pause";
\ No newline at end of file diff --git a/uu_more/options/constant.NUMBER.html b/uu_more/options/constant.NUMBER.html new file mode 100644 index 000000000..d6b3b02e0 --- /dev/null +++ b/uu_more/options/constant.NUMBER.html @@ -0,0 +1,3 @@ +NUMBER in uu_more::options - Rust + +

Constant uu_more::options::NUMBER[][src]

pub const NUMBER: &str = "number";
\ No newline at end of file diff --git a/uu_more/options/constant.PATTERN.html b/uu_more/options/constant.PATTERN.html new file mode 100644 index 000000000..1ae945035 --- /dev/null +++ b/uu_more/options/constant.PATTERN.html @@ -0,0 +1,3 @@ +PATTERN in uu_more::options - Rust + +

Constant uu_more::options::PATTERN[][src]

pub const PATTERN: &str = "pattern";
\ No newline at end of file diff --git a/uu_more/options/constant.PLAIN.html b/uu_more/options/constant.PLAIN.html new file mode 100644 index 000000000..5c2ce2add --- /dev/null +++ b/uu_more/options/constant.PLAIN.html @@ -0,0 +1,3 @@ +PLAIN in uu_more::options - Rust + +

Constant uu_more::options::PLAIN[][src]

pub const PLAIN: &str = "plain";
\ No newline at end of file diff --git a/uu_more/options/constant.PRINT_OVER.html b/uu_more/options/constant.PRINT_OVER.html new file mode 100644 index 000000000..67bf4d2c3 --- /dev/null +++ b/uu_more/options/constant.PRINT_OVER.html @@ -0,0 +1,3 @@ +PRINT_OVER in uu_more::options - Rust + +

Constant uu_more::options::PRINT_OVER[][src]

pub const PRINT_OVER: &str = "print-over";
\ No newline at end of file diff --git a/uu_more/options/constant.SILENT.html b/uu_more/options/constant.SILENT.html new file mode 100644 index 000000000..9e8ababcd --- /dev/null +++ b/uu_more/options/constant.SILENT.html @@ -0,0 +1,3 @@ +SILENT in uu_more::options - Rust + +

Constant uu_more::options::SILENT[][src]

pub const SILENT: &str = "silent";
\ No newline at end of file diff --git a/uu_more/options/constant.SQUEEZE.html b/uu_more/options/constant.SQUEEZE.html new file mode 100644 index 000000000..09a3a5610 --- /dev/null +++ b/uu_more/options/constant.SQUEEZE.html @@ -0,0 +1,3 @@ +SQUEEZE in uu_more::options - Rust + +

Constant uu_more::options::SQUEEZE[][src]

pub const SQUEEZE: &str = "squeeze";
\ No newline at end of file diff --git a/uu_more/options/index.html b/uu_more/options/index.html new file mode 100644 index 000000000..efc9fa430 --- /dev/null +++ b/uu_more/options/index.html @@ -0,0 +1,4 @@ +uu_more::options - Rust + +

Module uu_more::options[][src]

Constants

+
CLEAN_PRINT
FILES
FROM_LINE
LINES
LOGICAL
NO_PAUSE
NUMBER
PATTERN
PLAIN
PRINT_OVER
SILENT
SQUEEZE
\ No newline at end of file diff --git a/uu_more/options/sidebar-items.js b/uu_more/options/sidebar-items.js new file mode 100644 index 000000000..bf558e2e7 --- /dev/null +++ b/uu_more/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["CLEAN_PRINT",""],["FILES",""],["FROM_LINE",""],["LINES",""],["LOGICAL",""],["NO_PAUSE",""],["NUMBER",""],["PATTERN",""],["PLAIN",""],["PRINT_OVER",""],["SILENT",""],["SQUEEZE",""]]}); \ No newline at end of file diff --git a/uu_more/sidebar-items.js b/uu_more/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_more/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_mv/all.html b/uu_mv/all.html new file mode 100644 index 000000000..9dcc78d40 --- /dev/null +++ b/uu_mv/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Functions

\ No newline at end of file diff --git a/uu_mv/enum.OverwriteMode.html b/uu_mv/enum.OverwriteMode.html new file mode 100644 index 000000000..e049f8179 --- /dev/null +++ b/uu_mv/enum.OverwriteMode.html @@ -0,0 +1,27 @@ +OverwriteMode in uu_mv - Rust + +

Enum uu_mv::OverwriteMode[][src]

pub enum OverwriteMode {
+    NoClobber,
+    Interactive,
+    Force,
+}

+ Variants

+
NoClobber
Interactive
Force

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_mv/fn.uu_app.html b/uu_mv/fn.uu_app.html new file mode 100644 index 000000000..5c553216d --- /dev/null +++ b/uu_mv/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_mv - Rust + +

Function uu_mv::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_mv/fn.uumain.html b/uu_mv/fn.uumain.html new file mode 100644 index 000000000..37d5bc23b --- /dev/null +++ b/uu_mv/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_mv - Rust + +

Function uu_mv::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_mv/index.html b/uu_mv/index.html new file mode 100644 index 000000000..1e2697606 --- /dev/null +++ b/uu_mv/index.html @@ -0,0 +1,6 @@ +uu_mv - Rust + +

Crate uu_mv[][src]

Structs

+
Behavior

Enums

+
OverwriteMode

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_mv/sidebar-items.js b/uu_mv/sidebar-items.js new file mode 100644 index 000000000..d9d07c390 --- /dev/null +++ b/uu_mv/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["OverwriteMode",""]],"fn":[["uu_app",""],["uumain",""]],"struct":[["Behavior",""]]}); \ No newline at end of file diff --git a/uu_mv/struct.Behavior.html b/uu_mv/struct.Behavior.html new file mode 100644 index 000000000..0259d1e53 --- /dev/null +++ b/uu_mv/struct.Behavior.html @@ -0,0 +1,12 @@ +Behavior in uu_mv - Rust + +

Struct uu_mv::Behavior[][src]

pub struct Behavior { /* fields omitted */ }

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_nice/all.html b/uu_nice/all.html new file mode 100644 index 000000000..2bbacaf05 --- /dev/null +++ b/uu_nice/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_nice/fn.uu_app.html b/uu_nice/fn.uu_app.html new file mode 100644 index 000000000..9ce64ec3e --- /dev/null +++ b/uu_nice/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_nice - Rust + +

Function uu_nice::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_nice/fn.uumain.html b/uu_nice/fn.uumain.html new file mode 100644 index 000000000..3b3839909 --- /dev/null +++ b/uu_nice/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_nice - Rust + +

Function uu_nice::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_nice/index.html b/uu_nice/index.html new file mode 100644 index 000000000..fafdf733f --- /dev/null +++ b/uu_nice/index.html @@ -0,0 +1,5 @@ +uu_nice - Rust + +

Crate uu_nice[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_nice/options/index.html b/uu_nice/options/index.html new file mode 100644 index 000000000..f73592e66 --- /dev/null +++ b/uu_nice/options/index.html @@ -0,0 +1,4 @@ +uu_nice::options - Rust + +

Module uu_nice::options[][src]

Statics

+
ADJUSTMENT
COMMAND
\ No newline at end of file diff --git a/uu_nice/options/sidebar-items.js b/uu_nice/options/sidebar-items.js new file mode 100644 index 000000000..d5f7600d9 --- /dev/null +++ b/uu_nice/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ADJUSTMENT",""],["COMMAND",""]]}); \ No newline at end of file diff --git a/uu_nice/options/static.ADJUSTMENT.html b/uu_nice/options/static.ADJUSTMENT.html new file mode 100644 index 000000000..5ec954cb7 --- /dev/null +++ b/uu_nice/options/static.ADJUSTMENT.html @@ -0,0 +1,3 @@ +ADJUSTMENT in uu_nice::options - Rust + +

Static uu_nice::options::ADJUSTMENT[][src]

pub static ADJUSTMENT: &str
\ No newline at end of file diff --git a/uu_nice/options/static.COMMAND.html b/uu_nice/options/static.COMMAND.html new file mode 100644 index 000000000..e9cb538c3 --- /dev/null +++ b/uu_nice/options/static.COMMAND.html @@ -0,0 +1,3 @@ +COMMAND in uu_nice::options - Rust + +

Static uu_nice::options::COMMAND[][src]

pub static COMMAND: &str
\ No newline at end of file diff --git a/uu_nice/sidebar-items.js b/uu_nice/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_nice/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_nl/all.html b/uu_nl/all.html new file mode 100644 index 000000000..fed6a14a2 --- /dev/null +++ b/uu_nl/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Functions

Constants

\ No newline at end of file diff --git a/uu_nl/fn.uu_app.html b/uu_nl/fn.uu_app.html new file mode 100644 index 000000000..cebd77813 --- /dev/null +++ b/uu_nl/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_nl - Rust + +

Function uu_nl::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_nl/fn.uumain.html b/uu_nl/fn.uumain.html new file mode 100644 index 000000000..83197ce1f --- /dev/null +++ b/uu_nl/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_nl - Rust + +

Function uu_nl::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_nl/index.html b/uu_nl/index.html new file mode 100644 index 000000000..5e644a598 --- /dev/null +++ b/uu_nl/index.html @@ -0,0 +1,6 @@ +uu_nl - Rust + +

Crate uu_nl[][src]

Modules

+
options

Structs

+
Settings

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_nl/options/constant.BODY_NUMBERING.html b/uu_nl/options/constant.BODY_NUMBERING.html new file mode 100644 index 000000000..9a65c67c1 --- /dev/null +++ b/uu_nl/options/constant.BODY_NUMBERING.html @@ -0,0 +1,3 @@ +BODY_NUMBERING in uu_nl::options - Rust + +

Constant uu_nl::options::BODY_NUMBERING[][src]

pub const BODY_NUMBERING: &str = "body-numbering";
\ No newline at end of file diff --git a/uu_nl/options/constant.FILE.html b/uu_nl/options/constant.FILE.html new file mode 100644 index 000000000..4a03b29dc --- /dev/null +++ b/uu_nl/options/constant.FILE.html @@ -0,0 +1,3 @@ +FILE in uu_nl::options - Rust + +

Constant uu_nl::options::FILE[][src]

pub const FILE: &str = "file";
\ No newline at end of file diff --git a/uu_nl/options/constant.FOOTER_NUMBERING.html b/uu_nl/options/constant.FOOTER_NUMBERING.html new file mode 100644 index 000000000..7b4f1f32e --- /dev/null +++ b/uu_nl/options/constant.FOOTER_NUMBERING.html @@ -0,0 +1,3 @@ +FOOTER_NUMBERING in uu_nl::options - Rust + +

Constant uu_nl::options::FOOTER_NUMBERING[][src]

pub const FOOTER_NUMBERING: &str = "footer-numbering";
\ No newline at end of file diff --git a/uu_nl/options/constant.HEADER_NUMBERING.html b/uu_nl/options/constant.HEADER_NUMBERING.html new file mode 100644 index 000000000..1ac205ff1 --- /dev/null +++ b/uu_nl/options/constant.HEADER_NUMBERING.html @@ -0,0 +1,3 @@ +HEADER_NUMBERING in uu_nl::options - Rust + +

Constant uu_nl::options::HEADER_NUMBERING[][src]

pub const HEADER_NUMBERING: &str = "header-numbering";
\ No newline at end of file diff --git a/uu_nl/options/constant.JOIN_BLANK_LINES.html b/uu_nl/options/constant.JOIN_BLANK_LINES.html new file mode 100644 index 000000000..f6a2b5432 --- /dev/null +++ b/uu_nl/options/constant.JOIN_BLANK_LINES.html @@ -0,0 +1,3 @@ +JOIN_BLANK_LINES in uu_nl::options - Rust + +

Constant uu_nl::options::JOIN_BLANK_LINES[][src]

pub const JOIN_BLANK_LINES: &str = "join-blank-lines";
\ No newline at end of file diff --git a/uu_nl/options/constant.LINE_INCREMENT.html b/uu_nl/options/constant.LINE_INCREMENT.html new file mode 100644 index 000000000..2f4bd7d4d --- /dev/null +++ b/uu_nl/options/constant.LINE_INCREMENT.html @@ -0,0 +1,3 @@ +LINE_INCREMENT in uu_nl::options - Rust + +

Constant uu_nl::options::LINE_INCREMENT[][src]

pub const LINE_INCREMENT: &str = "line-increment";
\ No newline at end of file diff --git a/uu_nl/options/constant.NO_RENUMBER.html b/uu_nl/options/constant.NO_RENUMBER.html new file mode 100644 index 000000000..bed211dda --- /dev/null +++ b/uu_nl/options/constant.NO_RENUMBER.html @@ -0,0 +1,3 @@ +NO_RENUMBER in uu_nl::options - Rust + +

Constant uu_nl::options::NO_RENUMBER[][src]

pub const NO_RENUMBER: &str = "no-renumber";
\ No newline at end of file diff --git a/uu_nl/options/constant.NUMBER_FORMAT.html b/uu_nl/options/constant.NUMBER_FORMAT.html new file mode 100644 index 000000000..e024d1345 --- /dev/null +++ b/uu_nl/options/constant.NUMBER_FORMAT.html @@ -0,0 +1,3 @@ +NUMBER_FORMAT in uu_nl::options - Rust + +

Constant uu_nl::options::NUMBER_FORMAT[][src]

pub const NUMBER_FORMAT: &str = "number-format";
\ No newline at end of file diff --git a/uu_nl/options/constant.NUMBER_SEPARATOR.html b/uu_nl/options/constant.NUMBER_SEPARATOR.html new file mode 100644 index 000000000..62390af57 --- /dev/null +++ b/uu_nl/options/constant.NUMBER_SEPARATOR.html @@ -0,0 +1,3 @@ +NUMBER_SEPARATOR in uu_nl::options - Rust + +

Constant uu_nl::options::NUMBER_SEPARATOR[][src]

pub const NUMBER_SEPARATOR: &str = "number-separator";
\ No newline at end of file diff --git a/uu_nl/options/constant.NUMBER_WIDTH.html b/uu_nl/options/constant.NUMBER_WIDTH.html new file mode 100644 index 000000000..9bc548c47 --- /dev/null +++ b/uu_nl/options/constant.NUMBER_WIDTH.html @@ -0,0 +1,3 @@ +NUMBER_WIDTH in uu_nl::options - Rust + +

Constant uu_nl::options::NUMBER_WIDTH[][src]

pub const NUMBER_WIDTH: &str = "number-width";
\ No newline at end of file diff --git a/uu_nl/options/constant.SECTION_DELIMITER.html b/uu_nl/options/constant.SECTION_DELIMITER.html new file mode 100644 index 000000000..3839f2a82 --- /dev/null +++ b/uu_nl/options/constant.SECTION_DELIMITER.html @@ -0,0 +1,3 @@ +SECTION_DELIMITER in uu_nl::options - Rust + +

Constant uu_nl::options::SECTION_DELIMITER[][src]

pub const SECTION_DELIMITER: &str = "section-delimiter";
\ No newline at end of file diff --git a/uu_nl/options/constant.STARTING_LINE_NUMBER.html b/uu_nl/options/constant.STARTING_LINE_NUMBER.html new file mode 100644 index 000000000..d2a1546b2 --- /dev/null +++ b/uu_nl/options/constant.STARTING_LINE_NUMBER.html @@ -0,0 +1,3 @@ +STARTING_LINE_NUMBER in uu_nl::options - Rust + +

Constant uu_nl::options::STARTING_LINE_NUMBER[][src]

pub const STARTING_LINE_NUMBER: &str = "starting-line-number";
\ No newline at end of file diff --git a/uu_nl/options/index.html b/uu_nl/options/index.html new file mode 100644 index 000000000..c881e962a --- /dev/null +++ b/uu_nl/options/index.html @@ -0,0 +1,4 @@ +uu_nl::options - Rust + +

Module uu_nl::options[][src]

Constants

+
BODY_NUMBERING
FILE
FOOTER_NUMBERING
HEADER_NUMBERING
JOIN_BLANK_LINES
LINE_INCREMENT
NO_RENUMBER
NUMBER_FORMAT
NUMBER_SEPARATOR
NUMBER_WIDTH
SECTION_DELIMITER
STARTING_LINE_NUMBER
\ No newline at end of file diff --git a/uu_nl/options/sidebar-items.js b/uu_nl/options/sidebar-items.js new file mode 100644 index 000000000..c7b571608 --- /dev/null +++ b/uu_nl/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["BODY_NUMBERING",""],["FILE",""],["FOOTER_NUMBERING",""],["HEADER_NUMBERING",""],["JOIN_BLANK_LINES",""],["LINE_INCREMENT",""],["NO_RENUMBER",""],["NUMBER_FORMAT",""],["NUMBER_SEPARATOR",""],["NUMBER_WIDTH",""],["SECTION_DELIMITER",""],["STARTING_LINE_NUMBER",""]]}); \ No newline at end of file diff --git a/uu_nl/sidebar-items.js b/uu_nl/sidebar-items.js new file mode 100644 index 000000000..77f1a8c2d --- /dev/null +++ b/uu_nl/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]],"struct":[["Settings",""]]}); \ No newline at end of file diff --git a/uu_nl/struct.Settings.html b/uu_nl/struct.Settings.html new file mode 100644 index 000000000..e7e03aa63 --- /dev/null +++ b/uu_nl/struct.Settings.html @@ -0,0 +1,12 @@ +Settings in uu_nl - Rust + +

Struct uu_nl::Settings[][src]

pub struct Settings { /* fields omitted */ }

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_nohup/all.html b/uu_nohup/all.html new file mode 100644 index 000000000..8a473d737 --- /dev/null +++ b/uu_nohup/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_nohup/fn.uu_app.html b/uu_nohup/fn.uu_app.html new file mode 100644 index 000000000..1e42db7da --- /dev/null +++ b/uu_nohup/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_nohup - Rust + +

Function uu_nohup::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_nohup/fn.uumain.html b/uu_nohup/fn.uumain.html new file mode 100644 index 000000000..5d90da45b --- /dev/null +++ b/uu_nohup/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_nohup - Rust + +

Function uu_nohup::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_nohup/index.html b/uu_nohup/index.html new file mode 100644 index 000000000..aa5509085 --- /dev/null +++ b/uu_nohup/index.html @@ -0,0 +1,4 @@ +uu_nohup - Rust + +

Crate uu_nohup[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_nohup/sidebar-items.js b/uu_nohup/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_nohup/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_nproc/all.html b/uu_nproc/all.html new file mode 100644 index 000000000..e78ff26bc --- /dev/null +++ b/uu_nproc/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Constants

\ No newline at end of file diff --git a/uu_nproc/constant._SC_NPROCESSORS_CONF.html b/uu_nproc/constant._SC_NPROCESSORS_CONF.html new file mode 100644 index 000000000..4dd66cca9 --- /dev/null +++ b/uu_nproc/constant._SC_NPROCESSORS_CONF.html @@ -0,0 +1,3 @@ +_SC_NPROCESSORS_CONF in uu_nproc - Rust + +

Constant uu_nproc::_SC_NPROCESSORS_CONF[][src]

pub const _SC_NPROCESSORS_CONF: c_int = 83;
\ No newline at end of file diff --git a/uu_nproc/fn.uu_app.html b/uu_nproc/fn.uu_app.html new file mode 100644 index 000000000..37e0e5eb8 --- /dev/null +++ b/uu_nproc/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_nproc - Rust + +

Function uu_nproc::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_nproc/fn.uumain.html b/uu_nproc/fn.uumain.html new file mode 100644 index 000000000..b5e970563 --- /dev/null +++ b/uu_nproc/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_nproc - Rust + +

Function uu_nproc::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_nproc/index.html b/uu_nproc/index.html new file mode 100644 index 000000000..8d87c198a --- /dev/null +++ b/uu_nproc/index.html @@ -0,0 +1,5 @@ +uu_nproc - Rust + +

Crate uu_nproc[][src]

Constants

+
_SC_NPROCESSORS_CONF

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_nproc/sidebar-items.js b/uu_nproc/sidebar-items.js new file mode 100644 index 000000000..6e1b5c688 --- /dev/null +++ b/uu_nproc/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["_SC_NPROCESSORS_CONF",""]],"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_numfmt/all.html b/uu_numfmt/all.html new file mode 100644 index 000000000..876409cb5 --- /dev/null +++ b/uu_numfmt/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Functions

Constants

\ No newline at end of file diff --git a/uu_numfmt/fn.uu_app.html b/uu_numfmt/fn.uu_app.html new file mode 100644 index 000000000..5ef500e21 --- /dev/null +++ b/uu_numfmt/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_numfmt - Rust + +

Function uu_numfmt::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_numfmt/fn.uumain.html b/uu_numfmt/fn.uumain.html new file mode 100644 index 000000000..cb74221ad --- /dev/null +++ b/uu_numfmt/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_numfmt - Rust + +

Function uu_numfmt::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_numfmt/format/fn.div_round.html b/uu_numfmt/format/fn.div_round.html new file mode 100644 index 000000000..47cbc210e --- /dev/null +++ b/uu_numfmt/format/fn.div_round.html @@ -0,0 +1,25 @@ +div_round in uu_numfmt::format - Rust + +

Function uu_numfmt::format::div_round[][src]

pub fn div_round(n: f64, d: f64, method: RoundMethod) -> f64
Expand description

Divide numerator by denominator, with rounding.

+

If the result of the division is less than 10.0, round to one decimal point.

+

Otherwise, round to an integer.

+

Examples:

+
+use uu_numfmt::format::div_round;
+use uu_numfmt::options::RoundMethod;
+
+// Rounding methods:
+assert_eq!(div_round(1.01, 1.0, RoundMethod::FromZero), 1.1);
+assert_eq!(div_round(1.01, 1.0, RoundMethod::TowardsZero), 1.0);
+assert_eq!(div_round(1.01, 1.0, RoundMethod::Up), 1.1);
+assert_eq!(div_round(1.01, 1.0, RoundMethod::Down), 1.0);
+assert_eq!(div_round(1.01, 1.0, RoundMethod::Nearest), 1.0);
+
+// Division:
+assert_eq!(div_round(999.1, 1000.0, RoundMethod::FromZero), 1.0);
+assert_eq!(div_round(1001., 10., RoundMethod::FromZero), 101.);
+assert_eq!(div_round(9991., 10., RoundMethod::FromZero), 1000.);
+assert_eq!(div_round(-12.34, 1.0, RoundMethod::FromZero), -13.0);
+assert_eq!(div_round(1000.0, -3.14, RoundMethod::FromZero), -319.0);
+assert_eq!(div_round(-271828.0, -271.0, RoundMethod::FromZero), 1004.0);
+
\ No newline at end of file diff --git a/uu_numfmt/format/fn.format_and_print.html b/uu_numfmt/format/fn.format_and_print.html new file mode 100644 index 000000000..2c06c9437 --- /dev/null +++ b/uu_numfmt/format/fn.format_and_print.html @@ -0,0 +1,7 @@ +format_and_print in uu_numfmt::format - Rust + +

Function uu_numfmt::format::format_and_print[][src]

pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<(), String>
Expand description

Format a line of text according to the selected options.

+

Given a line of text s, split the line into fields, transform and format +any selected numeric fields, and print the result to stdout. Fields not +selected for conversion are passed through unmodified.

+
\ No newline at end of file diff --git a/uu_numfmt/format/index.html b/uu_numfmt/format/index.html new file mode 100644 index 000000000..131c67145 --- /dev/null +++ b/uu_numfmt/format/index.html @@ -0,0 +1,10 @@ +uu_numfmt::format - Rust + +

Module uu_numfmt::format[][src]

Structs

+
WhitespaceSplitter

Iterate over a line’s fields, where each field is a contiguous sequence of +non-whitespace, optionally prefixed with one or more characters of leading +whitespace. Fields are returned as tuples of (prefix, field).

+

Functions

+
div_round

Divide numerator by denominator, with rounding.

+
format_and_print

Format a line of text according to the selected options.

+
\ No newline at end of file diff --git a/uu_numfmt/format/sidebar-items.js b/uu_numfmt/format/sidebar-items.js new file mode 100644 index 000000000..cb7c6286a --- /dev/null +++ b/uu_numfmt/format/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["div_round","Divide numerator by denominator, with rounding."],["format_and_print","Format a line of text according to the selected options."]],"struct":[["WhitespaceSplitter","Iterate over a line’s fields, where each field is a contiguous sequence of non-whitespace, optionally prefixed with one or more characters of leading whitespace. Fields are returned as tuples of `(prefix, field)`."]]}); \ No newline at end of file diff --git a/uu_numfmt/format/struct.WhitespaceSplitter.html b/uu_numfmt/format/struct.WhitespaceSplitter.html new file mode 100644 index 000000000..c88ce80f1 --- /dev/null +++ b/uu_numfmt/format/struct.WhitespaceSplitter.html @@ -0,0 +1,158 @@ +WhitespaceSplitter in uu_numfmt::format - Rust + +

Struct uu_numfmt::format::WhitespaceSplitter[][src]

pub struct WhitespaceSplitter<'a> {
+    pub s: Option<&'a str>,
+}
Expand description

Iterate over a line’s fields, where each field is a contiguous sequence of +non-whitespace, optionally prefixed with one or more characters of leading +whitespace. Fields are returned as tuples of (prefix, field).

+

Examples:

+
+let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("    1234 5") };
+
+assert_eq!(Some(("    ", "1234")), fields.next());
+assert_eq!(Some((" ", "5")), fields.next());
+assert_eq!(None, fields.next());
+

Delimiters are included in the results; prefix will be empty only for +the first field of the line (including the case where the input line is +empty):

+ +
+let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
+
+assert_eq!(Some(("", "first")), fields.next());
+assert_eq!(Some((" ", "second")), fields.next());
+
+let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
+
+assert_eq!(Some(("", "")), fields.next());
+

+ Fields

s: Option<&'a str>

Trait Implementations

Yield the next field in the input string as a tuple (prefix, field).

+

The type of the elements being iterated over.

+

Returns the bounds on the remaining length of the iterator. Read more

+

Consumes the iterator, counting the number of iterations and returning it. Read more

+

Consumes the iterator, returning the last element. Read more

+
🔬 This is a nightly-only experimental API. (iter_advance_by)

recently added

+

Advances the iterator by n elements. Read more

+

Returns the nth element of the iterator. Read more

+

Creates an iterator starting at the same point, but stepping by +the given amount at each iteration. Read more

+

Takes two iterators and creates a new iterator over both in sequence. Read more

+

‘Zips up’ two iterators into a single iterator of pairs. Read more

+
🔬 This is a nightly-only experimental API. (iter_intersperse)

recently added

+

Creates a new iterator which places a copy of separator between adjacent +items of the original iterator. Read more

+
🔬 This is a nightly-only experimental API. (iter_intersperse)

recently added

+

Creates a new iterator which places an item generated by separator +between adjacent items of the original iterator. Read more

+

Takes a closure and creates an iterator which calls that closure on each +element. Read more

+

Calls a closure on each element of an iterator. Read more

+

Creates an iterator which uses a closure to determine if an element +should be yielded. Read more

+

Creates an iterator that both filters and maps. Read more

+

Creates an iterator which gives the current iteration count as well as +the next value. Read more

+

Creates an iterator which can use the peek and peek_mut methods +to look at the next element of the iterator without consuming it. See +their documentation for more information. Read more

+

Creates an iterator that skips elements based on a predicate. Read more

+

Creates an iterator that yields elements based on a predicate. Read more

+
🔬 This is a nightly-only experimental API. (iter_map_while)

recently added

+

Creates an iterator that both yields elements based on a predicate and maps. Read more

+

Creates an iterator that skips the first n elements. Read more

+

Creates an iterator that yields the first n elements, or fewer +if the underlying iterator ends sooner. Read more

+

An iterator adaptor similar to fold that holds internal state and +produces a new iterator. Read more

+

Creates an iterator that works like map, but flattens nested structure. Read more

+

Creates an iterator that flattens nested structure. Read more

+

Creates an iterator which ends after the first None. Read more

+

Does something with each element of an iterator, passing the value on. Read more

+

Borrows an iterator, rather than consuming it. Read more

+

Transforms an iterator into a collection. Read more

+

Consumes an iterator, creating two collections from it. Read more

+
🔬 This is a nightly-only experimental API. (iter_partition_in_place)

new API

+

Reorders the elements of this iterator in-place according to the given predicate, +such that all those that return true precede all those that return false. +Returns the number of true elements found. Read more

+
🔬 This is a nightly-only experimental API. (iter_is_partitioned)

new API

+

Checks if the elements of this iterator are partitioned according to the given predicate, +such that all those that return true precede all those that return false. Read more

+

An iterator method that applies a function as long as it returns +successfully, producing a single, final value. Read more

+

An iterator method that applies a fallible function to each item in the +iterator, stopping at the first error and returning that error. Read more

+

Folds every element into an accumulator by applying an operation, +returning the final result. Read more

+

Reduces the elements to a single one, by repeatedly applying a reducing +operation. Read more

+

Tests if every element of the iterator matches a predicate. Read more

+

Tests if any element of the iterator matches a predicate. Read more

+

Searches for an element of an iterator that satisfies a predicate. Read more

+

Applies function to the elements of iterator and returns +the first non-none result. Read more

+
🔬 This is a nightly-only experimental API. (try_find)

new API

+

Applies function to the elements of iterator and returns +the first true result or the first error. Read more

+

Searches for an element in an iterator, returning its index. Read more

+

Searches for an element in an iterator from the right, returning its +index. Read more

+

Returns the maximum element of an iterator. Read more

+

Returns the minimum element of an iterator. Read more

+

Returns the element that gives the maximum value from the +specified function. Read more

+

Returns the element that gives the maximum value with respect to the +specified comparison function. Read more

+

Returns the element that gives the minimum value from the +specified function. Read more

+

Returns the element that gives the minimum value with respect to the +specified comparison function. Read more

+

Reverses an iterator’s direction. Read more

+

Converts an iterator of pairs into a pair of containers. Read more

+

Creates an iterator which copies all of its elements. Read more

+

Creates an iterator which clones all of its elements. Read more

+

Repeats an iterator endlessly. Read more

+

Sums the elements of an iterator. Read more

+

Iterates over the entire iterator, multiplying all the elements Read more

+

Lexicographically compares the elements of this Iterator with those +of another. Read more

+
🔬 This is a nightly-only experimental API. (iter_order_by)

Lexicographically compares the elements of this Iterator with those +of another with respect to the specified comparison function. Read more

+

Lexicographically compares the elements of this Iterator with those +of another. Read more

+
🔬 This is a nightly-only experimental API. (iter_order_by)

Lexicographically compares the elements of this Iterator with those +of another with respect to the specified comparison function. Read more

+

Determines if the elements of this Iterator are equal to those of +another. Read more

+
🔬 This is a nightly-only experimental API. (iter_order_by)

Determines if the elements of this Iterator are equal to those of +another with respect to the specified equality function. Read more

+

Determines if the elements of this Iterator are unequal to those of +another. Read more

+

Determines if the elements of this Iterator are lexicographically +less than those of another. Read more

+

Determines if the elements of this Iterator are lexicographically +less or equal to those of another. Read more

+

Determines if the elements of this Iterator are lexicographically +greater than those of another. Read more

+

Determines if the elements of this Iterator are lexicographically +greater than or equal to those of another. Read more

+
🔬 This is a nightly-only experimental API. (is_sorted)

new API

+

Checks if the elements of this iterator are sorted. Read more

+
🔬 This is a nightly-only experimental API. (is_sorted)

new API

+

Checks if the elements of this iterator are sorted using the given comparator function. Read more

+
🔬 This is a nightly-only experimental API. (is_sorted)

new API

+

Checks if the elements of this iterator are sorted using the given key extraction +function. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type of the elements being iterated over.

+

Which kind of iterator are we turning this into?

+

Creates an iterator from a value. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_numfmt/index.html b/uu_numfmt/index.html new file mode 100644 index 000000000..990ad8579 --- /dev/null +++ b/uu_numfmt/index.html @@ -0,0 +1,5 @@ +uu_numfmt - Rust + +

Crate uu_numfmt[][src]

Modules

+
format
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_numfmt/options/constant.DELIMITER.html b/uu_numfmt/options/constant.DELIMITER.html new file mode 100644 index 000000000..cc3e16557 --- /dev/null +++ b/uu_numfmt/options/constant.DELIMITER.html @@ -0,0 +1,3 @@ +DELIMITER in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::DELIMITER[][src]

pub const DELIMITER: &str = "delimiter";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.FIELD.html b/uu_numfmt/options/constant.FIELD.html new file mode 100644 index 000000000..c3c08966b --- /dev/null +++ b/uu_numfmt/options/constant.FIELD.html @@ -0,0 +1,3 @@ +FIELD in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::FIELD[][src]

pub const FIELD: &str = "field";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.FIELD_DEFAULT.html b/uu_numfmt/options/constant.FIELD_DEFAULT.html new file mode 100644 index 000000000..45f1c7ef6 --- /dev/null +++ b/uu_numfmt/options/constant.FIELD_DEFAULT.html @@ -0,0 +1,3 @@ +FIELD_DEFAULT in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::FIELD_DEFAULT[][src]

pub const FIELD_DEFAULT: &str = "1";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.FROM.html b/uu_numfmt/options/constant.FROM.html new file mode 100644 index 000000000..f05ea0d87 --- /dev/null +++ b/uu_numfmt/options/constant.FROM.html @@ -0,0 +1,3 @@ +FROM in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::FROM[][src]

pub const FROM: &str = "from";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.FROM_DEFAULT.html b/uu_numfmt/options/constant.FROM_DEFAULT.html new file mode 100644 index 000000000..b3e4adc4f --- /dev/null +++ b/uu_numfmt/options/constant.FROM_DEFAULT.html @@ -0,0 +1,3 @@ +FROM_DEFAULT in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::FROM_DEFAULT[][src]

pub const FROM_DEFAULT: &str = "none";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.HEADER.html b/uu_numfmt/options/constant.HEADER.html new file mode 100644 index 000000000..3af14330d --- /dev/null +++ b/uu_numfmt/options/constant.HEADER.html @@ -0,0 +1,3 @@ +HEADER in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::HEADER[][src]

pub const HEADER: &str = "header";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.HEADER_DEFAULT.html b/uu_numfmt/options/constant.HEADER_DEFAULT.html new file mode 100644 index 000000000..8c0e207a4 --- /dev/null +++ b/uu_numfmt/options/constant.HEADER_DEFAULT.html @@ -0,0 +1,3 @@ +HEADER_DEFAULT in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::HEADER_DEFAULT[][src]

pub const HEADER_DEFAULT: &str = "1";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.NUMBER.html b/uu_numfmt/options/constant.NUMBER.html new file mode 100644 index 000000000..2053fafbf --- /dev/null +++ b/uu_numfmt/options/constant.NUMBER.html @@ -0,0 +1,3 @@ +NUMBER in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::NUMBER[][src]

pub const NUMBER: &str = "NUMBER";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.PADDING.html b/uu_numfmt/options/constant.PADDING.html new file mode 100644 index 000000000..2ab554fb7 --- /dev/null +++ b/uu_numfmt/options/constant.PADDING.html @@ -0,0 +1,3 @@ +PADDING in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::PADDING[][src]

pub const PADDING: &str = "padding";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.ROUND.html b/uu_numfmt/options/constant.ROUND.html new file mode 100644 index 000000000..c0c5af0a5 --- /dev/null +++ b/uu_numfmt/options/constant.ROUND.html @@ -0,0 +1,3 @@ +ROUND in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::ROUND[][src]

pub const ROUND: &str = "round";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.TO.html b/uu_numfmt/options/constant.TO.html new file mode 100644 index 000000000..7a610d3a4 --- /dev/null +++ b/uu_numfmt/options/constant.TO.html @@ -0,0 +1,3 @@ +TO in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::TO[][src]

pub const TO: &str = "to";
\ No newline at end of file diff --git a/uu_numfmt/options/constant.TO_DEFAULT.html b/uu_numfmt/options/constant.TO_DEFAULT.html new file mode 100644 index 000000000..010c139d8 --- /dev/null +++ b/uu_numfmt/options/constant.TO_DEFAULT.html @@ -0,0 +1,3 @@ +TO_DEFAULT in uu_numfmt::options - Rust + +

Constant uu_numfmt::options::TO_DEFAULT[][src]

pub const TO_DEFAULT: &str = "none";
\ No newline at end of file diff --git a/uu_numfmt/options/enum.RoundMethod.html b/uu_numfmt/options/enum.RoundMethod.html new file mode 100644 index 000000000..5c63c7e84 --- /dev/null +++ b/uu_numfmt/options/enum.RoundMethod.html @@ -0,0 +1,26 @@ +RoundMethod in uu_numfmt::options - Rust + +

Enum uu_numfmt::options::RoundMethod[][src]

pub enum RoundMethod {
+    Up,
+    Down,
+    FromZero,
+    TowardsZero,
+    Nearest,
+}

+ Variants

+
Up
Down
FromZero
TowardsZero
Nearest

Implementations

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_numfmt/options/index.html b/uu_numfmt/options/index.html new file mode 100644 index 000000000..7320ae401 --- /dev/null +++ b/uu_numfmt/options/index.html @@ -0,0 +1,6 @@ +uu_numfmt::options - Rust + +

Module uu_numfmt::options[][src]

Structs

+
NumfmtOptions
TransformOptions

Enums

+
RoundMethod

Constants

+
DELIMITER
FIELD
FIELD_DEFAULT
FROM
FROM_DEFAULT
HEADER
HEADER_DEFAULT
NUMBER
PADDING
ROUND
TO
TO_DEFAULT
\ No newline at end of file diff --git a/uu_numfmt/options/sidebar-items.js b/uu_numfmt/options/sidebar-items.js new file mode 100644 index 000000000..a0f473c17 --- /dev/null +++ b/uu_numfmt/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["DELIMITER",""],["FIELD",""],["FIELD_DEFAULT",""],["FROM",""],["FROM_DEFAULT",""],["HEADER",""],["HEADER_DEFAULT",""],["NUMBER",""],["PADDING",""],["ROUND",""],["TO",""],["TO_DEFAULT",""]],"enum":[["RoundMethod",""]],"struct":[["NumfmtOptions",""],["TransformOptions",""]]}); \ No newline at end of file diff --git a/uu_numfmt/options/struct.NumfmtOptions.html b/uu_numfmt/options/struct.NumfmtOptions.html new file mode 100644 index 000000000..88bdda3c3 --- /dev/null +++ b/uu_numfmt/options/struct.NumfmtOptions.html @@ -0,0 +1,20 @@ +NumfmtOptions in uu_numfmt::options - Rust + +

Struct uu_numfmt::options::NumfmtOptions[][src]

pub struct NumfmtOptions {
+    pub transform: TransformOptions,
+    pub padding: isize,
+    pub header: usize,
+    pub fields: Vec<Range>,
+    pub delimiter: Option<String>,
+    pub round: RoundMethod,
+}

+ Fields

transform: TransformOptionspadding: isizeheader: usizefields: Vec<Range>delimiter: Option<String>round: RoundMethod

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_numfmt/options/struct.TransformOptions.html b/uu_numfmt/options/struct.TransformOptions.html new file mode 100644 index 000000000..f551dbeae --- /dev/null +++ b/uu_numfmt/options/struct.TransformOptions.html @@ -0,0 +1,16 @@ +TransformOptions in uu_numfmt::options - Rust + +

Struct uu_numfmt::options::TransformOptions[][src]

pub struct TransformOptions {
+    pub from: Unit,
+    pub to: Unit,
+}

+ Fields

from: Unitto: Unit

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_numfmt/sidebar-items.js b/uu_numfmt/sidebar-items.js new file mode 100644 index 000000000..896ccb0e9 --- /dev/null +++ b/uu_numfmt/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["format",""],["options",""]]}); \ No newline at end of file diff --git a/uu_od/all.html b/uu_od/all.html new file mode 100644 index 000000000..d6234a4ef --- /dev/null +++ b/uu_od/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_od/fn.uu_app.html b/uu_od/fn.uu_app.html new file mode 100644 index 000000000..98219b93d --- /dev/null +++ b/uu_od/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_od - Rust + +

Function uu_od::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_od/fn.uumain.html b/uu_od/fn.uumain.html new file mode 100644 index 000000000..ae57ecebc --- /dev/null +++ b/uu_od/fn.uumain.html @@ -0,0 +1,5 @@ +uumain in uu_od - Rust + +

Function uu_od::uumain[][src]

pub fn uumain(args: impl Args) -> i32
Expand description

parses and validates command line parameters, prepares data structures, +opens the input and calls odfunc to process the input.

+
\ No newline at end of file diff --git a/uu_od/index.html b/uu_od/index.html new file mode 100644 index 000000000..0d2fe162f --- /dev/null +++ b/uu_od/index.html @@ -0,0 +1,6 @@ +uu_od - Rust + +

Crate uu_od[][src]

Functions

+
uu_app
uumain

parses and validates command line parameters, prepares data structures, +opens the input and calls odfunc to process the input.

+
\ No newline at end of file diff --git a/uu_od/sidebar-items.js b/uu_od/sidebar-items.js new file mode 100644 index 000000000..059ad6383 --- /dev/null +++ b/uu_od/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain","parses and validates command line parameters, prepares data structures, opens the input and calls `odfunc` to process the input."]]}); \ No newline at end of file diff --git a/uu_paste/all.html b/uu_paste/all.html new file mode 100644 index 000000000..b2d62d8be --- /dev/null +++ b/uu_paste/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_paste/fn.uu_app.html b/uu_paste/fn.uu_app.html new file mode 100644 index 000000000..e85046903 --- /dev/null +++ b/uu_paste/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_paste - Rust + +

Function uu_paste::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_paste/fn.uumain.html b/uu_paste/fn.uumain.html new file mode 100644 index 000000000..508cc518f --- /dev/null +++ b/uu_paste/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_paste - Rust + +

Function uu_paste::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_paste/index.html b/uu_paste/index.html new file mode 100644 index 000000000..0decc03bf --- /dev/null +++ b/uu_paste/index.html @@ -0,0 +1,4 @@ +uu_paste - Rust + +

Crate uu_paste[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_paste/sidebar-items.js b/uu_paste/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_paste/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_pathchk/all.html b/uu_pathchk/all.html new file mode 100644 index 000000000..a224ad006 --- /dev/null +++ b/uu_pathchk/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_pathchk/fn.uu_app.html b/uu_pathchk/fn.uu_app.html new file mode 100644 index 000000000..0060d6304 --- /dev/null +++ b/uu_pathchk/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_pathchk - Rust + +

Function uu_pathchk::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_pathchk/fn.uumain.html b/uu_pathchk/fn.uumain.html new file mode 100644 index 000000000..0def05e1d --- /dev/null +++ b/uu_pathchk/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_pathchk - Rust + +

Function uu_pathchk::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_pathchk/index.html b/uu_pathchk/index.html new file mode 100644 index 000000000..8b2409adf --- /dev/null +++ b/uu_pathchk/index.html @@ -0,0 +1,4 @@ +uu_pathchk - Rust + +

Crate uu_pathchk[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_pathchk/sidebar-items.js b/uu_pathchk/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_pathchk/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_pinky/all.html b/uu_pinky/all.html new file mode 100644 index 000000000..5c7b4088b --- /dev/null +++ b/uu_pinky/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Traits

Functions

\ No newline at end of file diff --git a/uu_pinky/fn.uu_app.html b/uu_pinky/fn.uu_app.html new file mode 100644 index 000000000..5dd607478 --- /dev/null +++ b/uu_pinky/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_pinky - Rust + +

Function uu_pinky::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_pinky/fn.uumain.html b/uu_pinky/fn.uumain.html new file mode 100644 index 000000000..0fb5baa3b --- /dev/null +++ b/uu_pinky/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_pinky - Rust + +

Function uu_pinky::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_pinky/index.html b/uu_pinky/index.html new file mode 100644 index 000000000..198984284 --- /dev/null +++ b/uu_pinky/index.html @@ -0,0 +1,5 @@ +uu_pinky - Rust + +

Crate uu_pinky[][src]

Traits

+
Capitalize

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_pinky/sidebar-items.js b/uu_pinky/sidebar-items.js new file mode 100644 index 000000000..542aa165b --- /dev/null +++ b/uu_pinky/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"trait":[["Capitalize",""]]}); \ No newline at end of file diff --git a/uu_pinky/trait.Capitalize.html b/uu_pinky/trait.Capitalize.html new file mode 100644 index 000000000..6b162fdfa --- /dev/null +++ b/uu_pinky/trait.Capitalize.html @@ -0,0 +1,5 @@ +Capitalize in uu_pinky - Rust + +

Trait uu_pinky::Capitalize[][src]

pub trait Capitalize {
+    fn capitalize(&self) -> String;
+}

Required methods

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/uu_pr/all.html b/uu_pr/all.html new file mode 100644 index 000000000..1bcaa9688 --- /dev/null +++ b/uu_pr/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_pr/fn.uu_app.html b/uu_pr/fn.uu_app.html new file mode 100644 index 000000000..256c4eb61 --- /dev/null +++ b/uu_pr/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_pr - Rust + +

Function uu_pr::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_pr/fn.uumain.html b/uu_pr/fn.uumain.html new file mode 100644 index 000000000..8f9847a79 --- /dev/null +++ b/uu_pr/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_pr - Rust + +

Function uu_pr::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_pr/index.html b/uu_pr/index.html new file mode 100644 index 000000000..900ea2427 --- /dev/null +++ b/uu_pr/index.html @@ -0,0 +1,4 @@ +uu_pr - Rust + +

Crate uu_pr[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_pr/sidebar-items.js b/uu_pr/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_pr/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_printenv/all.html b/uu_printenv/all.html new file mode 100644 index 000000000..dcaf03eea --- /dev/null +++ b/uu_printenv/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_printenv/fn.uu_app.html b/uu_printenv/fn.uu_app.html new file mode 100644 index 000000000..5ac5de61f --- /dev/null +++ b/uu_printenv/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_printenv - Rust + +

Function uu_printenv::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_printenv/fn.uumain.html b/uu_printenv/fn.uumain.html new file mode 100644 index 000000000..715db1a02 --- /dev/null +++ b/uu_printenv/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_printenv - Rust + +

Function uu_printenv::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_printenv/index.html b/uu_printenv/index.html new file mode 100644 index 000000000..a38683783 --- /dev/null +++ b/uu_printenv/index.html @@ -0,0 +1,4 @@ +uu_printenv - Rust + +

Crate uu_printenv[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_printenv/sidebar-items.js b/uu_printenv/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_printenv/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_printf/all.html b/uu_printf/all.html new file mode 100644 index 000000000..e9679e600 --- /dev/null +++ b/uu_printf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_printf/fn.uu_app.html b/uu_printf/fn.uu_app.html new file mode 100644 index 000000000..582c40ab8 --- /dev/null +++ b/uu_printf/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_printf - Rust + +

Function uu_printf::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_printf/fn.uumain.html b/uu_printf/fn.uumain.html new file mode 100644 index 000000000..d6bbc100b --- /dev/null +++ b/uu_printf/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_printf - Rust + +

Function uu_printf::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_printf/index.html b/uu_printf/index.html new file mode 100644 index 000000000..de9354901 --- /dev/null +++ b/uu_printf/index.html @@ -0,0 +1,4 @@ +uu_printf - Rust + +

Crate uu_printf[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_printf/sidebar-items.js b/uu_printf/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_printf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_ptx/all.html b/uu_ptx/all.html new file mode 100644 index 000000000..931d351c4 --- /dev/null +++ b/uu_ptx/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_ptx/fn.uu_app.html b/uu_ptx/fn.uu_app.html new file mode 100644 index 000000000..2aa71aa5e --- /dev/null +++ b/uu_ptx/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_ptx - Rust + +

Function uu_ptx::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_ptx/fn.uumain.html b/uu_ptx/fn.uumain.html new file mode 100644 index 000000000..904b4e465 --- /dev/null +++ b/uu_ptx/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_ptx - Rust + +

Function uu_ptx::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_ptx/index.html b/uu_ptx/index.html new file mode 100644 index 000000000..3fec1898e --- /dev/null +++ b/uu_ptx/index.html @@ -0,0 +1,4 @@ +uu_ptx - Rust + +

Crate uu_ptx[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_ptx/sidebar-items.js b/uu_ptx/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_ptx/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_pwd/all.html b/uu_pwd/all.html new file mode 100644 index 000000000..9acf0abbf --- /dev/null +++ b/uu_pwd/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_pwd/fn.absolute_path.html b/uu_pwd/fn.absolute_path.html new file mode 100644 index 000000000..4f45cf98b --- /dev/null +++ b/uu_pwd/fn.absolute_path.html @@ -0,0 +1,3 @@ +absolute_path in uu_pwd - Rust + +

Function uu_pwd::absolute_path[][src]

pub fn absolute_path(path: &Path) -> Result<PathBuf>
\ No newline at end of file diff --git a/uu_pwd/fn.uu_app.html b/uu_pwd/fn.uu_app.html new file mode 100644 index 000000000..1eca1f3ef --- /dev/null +++ b/uu_pwd/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_pwd - Rust + +

Function uu_pwd::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_pwd/fn.uumain.html b/uu_pwd/fn.uumain.html new file mode 100644 index 000000000..52c38863c --- /dev/null +++ b/uu_pwd/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_pwd - Rust + +

Function uu_pwd::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_pwd/index.html b/uu_pwd/index.html new file mode 100644 index 000000000..0a3fb449b --- /dev/null +++ b/uu_pwd/index.html @@ -0,0 +1,4 @@ +uu_pwd - Rust + +

Crate uu_pwd[][src]

Functions

+
absolute_path
uu_app
uumain
\ No newline at end of file diff --git a/uu_pwd/sidebar-items.js b/uu_pwd/sidebar-items.js new file mode 100644 index 000000000..56bdbc80f --- /dev/null +++ b/uu_pwd/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["absolute_path",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_readlink/all.html b/uu_readlink/all.html new file mode 100644 index 000000000..2c0bafe7f --- /dev/null +++ b/uu_readlink/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_readlink/fn.uu_app.html b/uu_readlink/fn.uu_app.html new file mode 100644 index 000000000..5d9e49ace --- /dev/null +++ b/uu_readlink/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_readlink - Rust + +

Function uu_readlink::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_readlink/fn.uumain.html b/uu_readlink/fn.uumain.html new file mode 100644 index 000000000..6ac696bed --- /dev/null +++ b/uu_readlink/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_readlink - Rust + +

Function uu_readlink::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_readlink/index.html b/uu_readlink/index.html new file mode 100644 index 000000000..8f3eef686 --- /dev/null +++ b/uu_readlink/index.html @@ -0,0 +1,4 @@ +uu_readlink - Rust + +

Crate uu_readlink[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_readlink/sidebar-items.js b/uu_readlink/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_readlink/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_realpath/all.html b/uu_realpath/all.html new file mode 100644 index 000000000..096c2a280 --- /dev/null +++ b/uu_realpath/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_realpath/fn.uu_app.html b/uu_realpath/fn.uu_app.html new file mode 100644 index 000000000..01b6708fc --- /dev/null +++ b/uu_realpath/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_realpath - Rust + +

Function uu_realpath::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_realpath/fn.uumain.html b/uu_realpath/fn.uumain.html new file mode 100644 index 000000000..71b8219ff --- /dev/null +++ b/uu_realpath/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_realpath - Rust + +

Function uu_realpath::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_realpath/index.html b/uu_realpath/index.html new file mode 100644 index 000000000..273b7094c --- /dev/null +++ b/uu_realpath/index.html @@ -0,0 +1,4 @@ +uu_realpath - Rust + +

Crate uu_realpath[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_realpath/sidebar-items.js b/uu_realpath/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_realpath/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_relpath/all.html b/uu_relpath/all.html new file mode 100644 index 000000000..fc133c08c --- /dev/null +++ b/uu_relpath/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_relpath/fn.uu_app.html b/uu_relpath/fn.uu_app.html new file mode 100644 index 000000000..5e3eb9ce4 --- /dev/null +++ b/uu_relpath/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_relpath - Rust + +

Function uu_relpath::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_relpath/fn.uumain.html b/uu_relpath/fn.uumain.html new file mode 100644 index 000000000..12b20c34e --- /dev/null +++ b/uu_relpath/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_relpath - Rust + +

Function uu_relpath::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_relpath/index.html b/uu_relpath/index.html new file mode 100644 index 000000000..d1473e961 --- /dev/null +++ b/uu_relpath/index.html @@ -0,0 +1,4 @@ +uu_relpath - Rust + +

Crate uu_relpath[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_relpath/sidebar-items.js b/uu_relpath/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_relpath/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_rm/all.html b/uu_rm/all.html new file mode 100644 index 000000000..523f47774 --- /dev/null +++ b/uu_rm/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_rm/fn.uu_app.html b/uu_rm/fn.uu_app.html new file mode 100644 index 000000000..fc9c012d0 --- /dev/null +++ b/uu_rm/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_rm - Rust + +

Function uu_rm::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_rm/fn.uumain.html b/uu_rm/fn.uumain.html new file mode 100644 index 000000000..0be46d1bd --- /dev/null +++ b/uu_rm/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_rm - Rust + +

Function uu_rm::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_rm/index.html b/uu_rm/index.html new file mode 100644 index 000000000..f4902f49e --- /dev/null +++ b/uu_rm/index.html @@ -0,0 +1,4 @@ +uu_rm - Rust + +

Crate uu_rm[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_rm/sidebar-items.js b/uu_rm/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_rm/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_rmdir/all.html b/uu_rmdir/all.html new file mode 100644 index 000000000..38973be4f --- /dev/null +++ b/uu_rmdir/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_rmdir/fn.uu_app.html b/uu_rmdir/fn.uu_app.html new file mode 100644 index 000000000..919023edb --- /dev/null +++ b/uu_rmdir/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_rmdir - Rust + +

Function uu_rmdir::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_rmdir/fn.uumain.html b/uu_rmdir/fn.uumain.html new file mode 100644 index 000000000..efd8f1c5e --- /dev/null +++ b/uu_rmdir/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_rmdir - Rust + +

Function uu_rmdir::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_rmdir/index.html b/uu_rmdir/index.html new file mode 100644 index 000000000..8ea6911d8 --- /dev/null +++ b/uu_rmdir/index.html @@ -0,0 +1,4 @@ +uu_rmdir - Rust + +

Crate uu_rmdir[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_rmdir/sidebar-items.js b/uu_rmdir/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_rmdir/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_runcon/all.html b/uu_runcon/all.html new file mode 100644 index 000000000..17dea4b90 --- /dev/null +++ b/uu_runcon/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Constants

\ No newline at end of file diff --git a/uu_runcon/fn.uu_app.html b/uu_runcon/fn.uu_app.html new file mode 100644 index 000000000..d6ea92961 --- /dev/null +++ b/uu_runcon/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_runcon - Rust + +

Function uu_runcon::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_runcon/fn.uumain.html b/uu_runcon/fn.uumain.html new file mode 100644 index 000000000..046da14c8 --- /dev/null +++ b/uu_runcon/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_runcon - Rust + +

Function uu_runcon::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_runcon/index.html b/uu_runcon/index.html new file mode 100644 index 000000000..a0c436e16 --- /dev/null +++ b/uu_runcon/index.html @@ -0,0 +1,5 @@ +uu_runcon - Rust + +

Crate uu_runcon[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_runcon/options/constant.COMPUTE.html b/uu_runcon/options/constant.COMPUTE.html new file mode 100644 index 000000000..dd79f4829 --- /dev/null +++ b/uu_runcon/options/constant.COMPUTE.html @@ -0,0 +1,3 @@ +COMPUTE in uu_runcon::options - Rust + +

Constant uu_runcon::options::COMPUTE[][src]

pub const COMPUTE: &str = "compute";
\ No newline at end of file diff --git a/uu_runcon/options/constant.RANGE.html b/uu_runcon/options/constant.RANGE.html new file mode 100644 index 000000000..ae1068b47 --- /dev/null +++ b/uu_runcon/options/constant.RANGE.html @@ -0,0 +1,3 @@ +RANGE in uu_runcon::options - Rust + +

Constant uu_runcon::options::RANGE[][src]

pub const RANGE: &str = "range";
\ No newline at end of file diff --git a/uu_runcon/options/constant.ROLE.html b/uu_runcon/options/constant.ROLE.html new file mode 100644 index 000000000..abd139711 --- /dev/null +++ b/uu_runcon/options/constant.ROLE.html @@ -0,0 +1,3 @@ +ROLE in uu_runcon::options - Rust + +

Constant uu_runcon::options::ROLE[][src]

pub const ROLE: &str = "role";
\ No newline at end of file diff --git a/uu_runcon/options/constant.TYPE.html b/uu_runcon/options/constant.TYPE.html new file mode 100644 index 000000000..cdac0880e --- /dev/null +++ b/uu_runcon/options/constant.TYPE.html @@ -0,0 +1,3 @@ +TYPE in uu_runcon::options - Rust + +

Constant uu_runcon::options::TYPE[][src]

pub const TYPE: &str = "type";
\ No newline at end of file diff --git a/uu_runcon/options/constant.USER.html b/uu_runcon/options/constant.USER.html new file mode 100644 index 000000000..f56d29543 --- /dev/null +++ b/uu_runcon/options/constant.USER.html @@ -0,0 +1,3 @@ +USER in uu_runcon::options - Rust + +

Constant uu_runcon::options::USER[][src]

pub const USER: &str = "user";
\ No newline at end of file diff --git a/uu_runcon/options/index.html b/uu_runcon/options/index.html new file mode 100644 index 000000000..7d576b72c --- /dev/null +++ b/uu_runcon/options/index.html @@ -0,0 +1,4 @@ +uu_runcon::options - Rust + +

Module uu_runcon::options[][src]

Constants

+
COMPUTE
RANGE
ROLE
TYPE
USER
\ No newline at end of file diff --git a/uu_runcon/options/sidebar-items.js b/uu_runcon/options/sidebar-items.js new file mode 100644 index 000000000..a94cb3a65 --- /dev/null +++ b/uu_runcon/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["COMPUTE",""],["RANGE",""],["ROLE",""],["TYPE",""],["USER",""]]}); \ No newline at end of file diff --git a/uu_runcon/sidebar-items.js b/uu_runcon/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_runcon/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_seq/all.html b/uu_seq/all.html new file mode 100644 index 000000000..ba1ce4c49 --- /dev/null +++ b/uu_seq/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_seq/fn.uu_app.html b/uu_seq/fn.uu_app.html new file mode 100644 index 000000000..de67a442f --- /dev/null +++ b/uu_seq/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_seq - Rust + +

Function uu_seq::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_seq/fn.uumain.html b/uu_seq/fn.uumain.html new file mode 100644 index 000000000..c898ba00c --- /dev/null +++ b/uu_seq/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_seq - Rust + +

Function uu_seq::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_seq/index.html b/uu_seq/index.html new file mode 100644 index 000000000..56a2d748a --- /dev/null +++ b/uu_seq/index.html @@ -0,0 +1,4 @@ +uu_seq - Rust + +

Crate uu_seq[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_seq/sidebar-items.js b/uu_seq/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_seq/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_shred/all.html b/uu_shred/all.html new file mode 100644 index 000000000..e59398917 --- /dev/null +++ b/uu_shred/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Constants

\ No newline at end of file diff --git a/uu_shred/fn.uu_app.html b/uu_shred/fn.uu_app.html new file mode 100644 index 000000000..0283f9a0d --- /dev/null +++ b/uu_shred/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_shred - Rust + +

Function uu_shred::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_shred/fn.uumain.html b/uu_shred/fn.uumain.html new file mode 100644 index 000000000..a401c84ca --- /dev/null +++ b/uu_shred/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_shred - Rust + +

Function uu_shred::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_shred/index.html b/uu_shred/index.html new file mode 100644 index 000000000..189c9b947 --- /dev/null +++ b/uu_shred/index.html @@ -0,0 +1,5 @@ +uu_shred - Rust + +

Crate uu_shred[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_shred/options/constant.EXACT.html b/uu_shred/options/constant.EXACT.html new file mode 100644 index 000000000..6d2d8b5b6 --- /dev/null +++ b/uu_shred/options/constant.EXACT.html @@ -0,0 +1,3 @@ +EXACT in uu_shred::options - Rust + +

Constant uu_shred::options::EXACT[][src]

pub const EXACT: &str = "exact";
\ No newline at end of file diff --git a/uu_shred/options/constant.FILE.html b/uu_shred/options/constant.FILE.html new file mode 100644 index 000000000..03c74e3b2 --- /dev/null +++ b/uu_shred/options/constant.FILE.html @@ -0,0 +1,3 @@ +FILE in uu_shred::options - Rust + +

Constant uu_shred::options::FILE[][src]

pub const FILE: &str = "file";
\ No newline at end of file diff --git a/uu_shred/options/constant.FORCE.html b/uu_shred/options/constant.FORCE.html new file mode 100644 index 000000000..7eac806e0 --- /dev/null +++ b/uu_shred/options/constant.FORCE.html @@ -0,0 +1,3 @@ +FORCE in uu_shred::options - Rust + +

Constant uu_shred::options::FORCE[][src]

pub const FORCE: &str = "force";
\ No newline at end of file diff --git a/uu_shred/options/constant.ITERATIONS.html b/uu_shred/options/constant.ITERATIONS.html new file mode 100644 index 000000000..be3e21815 --- /dev/null +++ b/uu_shred/options/constant.ITERATIONS.html @@ -0,0 +1,3 @@ +ITERATIONS in uu_shred::options - Rust + +

Constant uu_shred::options::ITERATIONS[][src]

pub const ITERATIONS: &str = "iterations";
\ No newline at end of file diff --git a/uu_shred/options/constant.REMOVE.html b/uu_shred/options/constant.REMOVE.html new file mode 100644 index 000000000..b429eeee7 --- /dev/null +++ b/uu_shred/options/constant.REMOVE.html @@ -0,0 +1,3 @@ +REMOVE in uu_shred::options - Rust + +

Constant uu_shred::options::REMOVE[][src]

pub const REMOVE: &str = "remove";
\ No newline at end of file diff --git a/uu_shred/options/constant.SIZE.html b/uu_shred/options/constant.SIZE.html new file mode 100644 index 000000000..4e1951316 --- /dev/null +++ b/uu_shred/options/constant.SIZE.html @@ -0,0 +1,3 @@ +SIZE in uu_shred::options - Rust + +

Constant uu_shred::options::SIZE[][src]

pub const SIZE: &str = "size";
\ No newline at end of file diff --git a/uu_shred/options/constant.VERBOSE.html b/uu_shred/options/constant.VERBOSE.html new file mode 100644 index 000000000..e030e7941 --- /dev/null +++ b/uu_shred/options/constant.VERBOSE.html @@ -0,0 +1,3 @@ +VERBOSE in uu_shred::options - Rust + +

Constant uu_shred::options::VERBOSE[][src]

pub const VERBOSE: &str = "verbose";
\ No newline at end of file diff --git a/uu_shred/options/constant.ZERO.html b/uu_shred/options/constant.ZERO.html new file mode 100644 index 000000000..70259578b --- /dev/null +++ b/uu_shred/options/constant.ZERO.html @@ -0,0 +1,3 @@ +ZERO in uu_shred::options - Rust + +

Constant uu_shred::options::ZERO[][src]

pub const ZERO: &str = "zero";
\ No newline at end of file diff --git a/uu_shred/options/index.html b/uu_shred/options/index.html new file mode 100644 index 000000000..d6e5f2b2f --- /dev/null +++ b/uu_shred/options/index.html @@ -0,0 +1,4 @@ +uu_shred::options - Rust + +

Module uu_shred::options[][src]

Constants

+
EXACT
FILE
FORCE
ITERATIONS
REMOVE
SIZE
VERBOSE
ZERO
\ No newline at end of file diff --git a/uu_shred/options/sidebar-items.js b/uu_shred/options/sidebar-items.js new file mode 100644 index 000000000..2bc72aef5 --- /dev/null +++ b/uu_shred/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["EXACT",""],["FILE",""],["FORCE",""],["ITERATIONS",""],["REMOVE",""],["SIZE",""],["VERBOSE",""],["ZERO",""]]}); \ No newline at end of file diff --git a/uu_shred/sidebar-items.js b/uu_shred/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_shred/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_shuf/all.html b/uu_shuf/all.html new file mode 100644 index 000000000..bf41bc446 --- /dev/null +++ b/uu_shuf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_shuf/fn.uu_app.html b/uu_shuf/fn.uu_app.html new file mode 100644 index 000000000..8a289190b --- /dev/null +++ b/uu_shuf/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_shuf - Rust + +

Function uu_shuf::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_shuf/fn.uumain.html b/uu_shuf/fn.uumain.html new file mode 100644 index 000000000..9925c7e60 --- /dev/null +++ b/uu_shuf/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_shuf - Rust + +

Function uu_shuf::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_shuf/index.html b/uu_shuf/index.html new file mode 100644 index 000000000..96ded2278 --- /dev/null +++ b/uu_shuf/index.html @@ -0,0 +1,4 @@ +uu_shuf - Rust + +

Crate uu_shuf[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_shuf/sidebar-items.js b/uu_shuf/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_shuf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_sleep/all.html b/uu_sleep/all.html new file mode 100644 index 000000000..cd1677d61 --- /dev/null +++ b/uu_sleep/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_sleep/fn.uu_app.html b/uu_sleep/fn.uu_app.html new file mode 100644 index 000000000..df453b52f --- /dev/null +++ b/uu_sleep/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_sleep - Rust + +

Function uu_sleep::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_sleep/fn.uumain.html b/uu_sleep/fn.uumain.html new file mode 100644 index 000000000..4234f0860 --- /dev/null +++ b/uu_sleep/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_sleep - Rust + +

Function uu_sleep::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_sleep/index.html b/uu_sleep/index.html new file mode 100644 index 000000000..ce30f4c03 --- /dev/null +++ b/uu_sleep/index.html @@ -0,0 +1,4 @@ +uu_sleep - Rust + +

Crate uu_sleep[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_sleep/sidebar-items.js b/uu_sleep/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_sleep/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_sort/all.html b/uu_sort/all.html new file mode 100644 index 000000000..b8184338c --- /dev/null +++ b/uu_sort/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Functions

\ No newline at end of file diff --git a/uu_sort/enum.GeneralF64ParseResult.html b/uu_sort/enum.GeneralF64ParseResult.html new file mode 100644 index 000000000..cbd72832e --- /dev/null +++ b/uu_sort/enum.GeneralF64ParseResult.html @@ -0,0 +1,43 @@ +GeneralF64ParseResult in uu_sort - Rust + +

Enum uu_sort::GeneralF64ParseResult[][src]

pub enum GeneralF64ParseResult {
+    Invalid,
+    NaN,
+    NegInfinity,
+    Number(f64),
+    Infinity,
+}

+ Variants

+
Invalid
NaN
NegInfinity
Number(f64)
Infinity

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_sort/fn.uu_app.html b/uu_sort/fn.uu_app.html new file mode 100644 index 000000000..278dd49ad --- /dev/null +++ b/uu_sort/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_sort - Rust + +

Function uu_sort::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_sort/fn.uumain.html b/uu_sort/fn.uumain.html new file mode 100644 index 000000000..2acc0f242 --- /dev/null +++ b/uu_sort/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_sort - Rust + +

Function uu_sort::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_sort/index.html b/uu_sort/index.html new file mode 100644 index 000000000..d9b09e799 --- /dev/null +++ b/uu_sort/index.html @@ -0,0 +1,6 @@ +uu_sort - Rust + +

Crate uu_sort[][src]

Structs

+
GlobalSettings
Line
Output

Enums

+
GeneralF64ParseResult

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_sort/sidebar-items.js b/uu_sort/sidebar-items.js new file mode 100644 index 000000000..7dd5c4c0c --- /dev/null +++ b/uu_sort/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["GeneralF64ParseResult",""]],"fn":[["uu_app",""],["uumain",""]],"struct":[["GlobalSettings",""],["Line",""],["Output",""]]}); \ No newline at end of file diff --git a/uu_sort/struct.GlobalSettings.html b/uu_sort/struct.GlobalSettings.html new file mode 100644 index 000000000..d1dd8f581 --- /dev/null +++ b/uu_sort/struct.GlobalSettings.html @@ -0,0 +1,25 @@ +GlobalSettings in uu_sort - Rust + +

Struct uu_sort::GlobalSettings[][src]

pub struct GlobalSettings { /* fields omitted */ }

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Returns the “default value” for a type. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_sort/struct.Line.html b/uu_sort/struct.Line.html new file mode 100644 index 000000000..8c991613c --- /dev/null +++ b/uu_sort/struct.Line.html @@ -0,0 +1,25 @@ +Line in uu_sort - Rust + +

Struct uu_sort::Line[][src]

pub struct Line<'a> { /* fields omitted */ }

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_sort/struct.Output.html b/uu_sort/struct.Output.html new file mode 100644 index 000000000..70829d219 --- /dev/null +++ b/uu_sort/struct.Output.html @@ -0,0 +1,18 @@ +Output in uu_sort - Rust + +

Struct uu_sort::Output[][src]

pub struct Output { /* fields omitted */ }

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The alignment of pointer.

+

The type for initializers.

+

Initializes a with the given initializer. Read more

+

Dereferences the given pointer. Read more

+

Mutably dereferences the given pointer. Read more

+

Drops the object pointed to by the given pointer. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_split/all.html b/uu_split/all.html new file mode 100644 index 000000000..e121ed0b9 --- /dev/null +++ b/uu_split/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_split/fn.uu_app.html b/uu_split/fn.uu_app.html new file mode 100644 index 000000000..a8d14f652 --- /dev/null +++ b/uu_split/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_split - Rust + +

Function uu_split::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_split/fn.uumain.html b/uu_split/fn.uumain.html new file mode 100644 index 000000000..858dd1ff0 --- /dev/null +++ b/uu_split/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_split - Rust + +

Function uu_split::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_split/index.html b/uu_split/index.html new file mode 100644 index 000000000..3db6ef278 --- /dev/null +++ b/uu_split/index.html @@ -0,0 +1,4 @@ +uu_split - Rust + +

Crate uu_split[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_split/sidebar-items.js b/uu_split/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_split/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_stat/all.html b/uu_stat/all.html new file mode 100644 index 000000000..e0b612eff --- /dev/null +++ b/uu_stat/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Traits

Functions

Statics

Constants

\ No newline at end of file diff --git a/uu_stat/constant.F_ALTER.html b/uu_stat/constant.F_ALTER.html new file mode 100644 index 000000000..8b07c8436 --- /dev/null +++ b/uu_stat/constant.F_ALTER.html @@ -0,0 +1,3 @@ +F_ALTER in uu_stat - Rust + +

Constant uu_stat::F_ALTER[][src]

pub const F_ALTER: u8 = 1;
\ No newline at end of file diff --git a/uu_stat/constant.F_GROUP.html b/uu_stat/constant.F_GROUP.html new file mode 100644 index 000000000..21a831ec4 --- /dev/null +++ b/uu_stat/constant.F_GROUP.html @@ -0,0 +1,3 @@ +F_GROUP in uu_stat - Rust + +

Constant uu_stat::F_GROUP[][src]

pub const F_GROUP: u8 = 1 << 5; // 0x20u8
\ No newline at end of file diff --git a/uu_stat/constant.F_LEFT.html b/uu_stat/constant.F_LEFT.html new file mode 100644 index 000000000..0bcbc9b08 --- /dev/null +++ b/uu_stat/constant.F_LEFT.html @@ -0,0 +1,3 @@ +F_LEFT in uu_stat - Rust + +

Constant uu_stat::F_LEFT[][src]

pub const F_LEFT: u8 = 1 << 2; // 0x04u8
\ No newline at end of file diff --git a/uu_stat/constant.F_SIGN.html b/uu_stat/constant.F_SIGN.html new file mode 100644 index 000000000..4b3d83906 --- /dev/null +++ b/uu_stat/constant.F_SIGN.html @@ -0,0 +1,3 @@ +F_SIGN in uu_stat - Rust + +

Constant uu_stat::F_SIGN[][src]

pub const F_SIGN: u8 = 1 << 4; // 0x10u8
\ No newline at end of file diff --git a/uu_stat/constant.F_SPACE.html b/uu_stat/constant.F_SPACE.html new file mode 100644 index 000000000..7c3ff7825 --- /dev/null +++ b/uu_stat/constant.F_SPACE.html @@ -0,0 +1,3 @@ +F_SPACE in uu_stat - Rust + +

Constant uu_stat::F_SPACE[][src]

pub const F_SPACE: u8 = 1 << 3; // 0x08u8
\ No newline at end of file diff --git a/uu_stat/constant.F_ZERO.html b/uu_stat/constant.F_ZERO.html new file mode 100644 index 000000000..06647259f --- /dev/null +++ b/uu_stat/constant.F_ZERO.html @@ -0,0 +1,3 @@ +F_ZERO in uu_stat - Rust + +

Constant uu_stat::F_ZERO[][src]

pub const F_ZERO: u8 = 1 << 1; // 0x02u8
\ No newline at end of file diff --git a/uu_stat/enum.OutputType.html b/uu_stat/enum.OutputType.html new file mode 100644 index 000000000..364708673 --- /dev/null +++ b/uu_stat/enum.OutputType.html @@ -0,0 +1,25 @@ +OutputType in uu_stat - Rust + +

Enum uu_stat::OutputType[][src]

pub enum OutputType {
+    Str,
+    Integer,
+    Unsigned,
+    UnsignedHex,
+    UnsignedOct,
+    Unknown,
+}

+ Variants

+
Str
Integer
Unsigned
UnsignedHex
UnsignedOct
Unknown

Trait Implementations

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_stat/enum.Token.html b/uu_stat/enum.Token.html new file mode 100644 index 000000000..7860320ce --- /dev/null +++ b/uu_stat/enum.Token.html @@ -0,0 +1,26 @@ +Token in uu_stat - Rust + +

Enum uu_stat::Token[][src]

pub enum Token {
+    Char(char),
+    Directive {
+        flag: u8,
+        width: usize,
+        precision: i32,
+        format: char,
+    },
+}

+ Variants

+
Char(char)
Directive
Show fields

Fields of Directive

flag: u8width: usizeprecision: i32format: char

Trait Implementations

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_stat/fn.group_num.html b/uu_stat/fn.group_num.html new file mode 100644 index 000000000..0256aee08 --- /dev/null +++ b/uu_stat/fn.group_num.html @@ -0,0 +1,3 @@ +group_num in uu_stat - Rust + +

Function uu_stat::group_num[][src]

pub fn group_num(s: &str) -> Cow<'_, str>
\ No newline at end of file diff --git a/uu_stat/fn.uu_app.html b/uu_stat/fn.uu_app.html new file mode 100644 index 000000000..47e46b64b --- /dev/null +++ b/uu_stat/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_stat - Rust + +

Function uu_stat::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_stat/fn.uumain.html b/uu_stat/fn.uumain.html new file mode 100644 index 000000000..c116cfa4d --- /dev/null +++ b/uu_stat/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_stat - Rust + +

Function uu_stat::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_stat/index.html b/uu_stat/index.html new file mode 100644 index 000000000..03536bc5f --- /dev/null +++ b/uu_stat/index.html @@ -0,0 +1,9 @@ +uu_stat - Rust + +

Crate uu_stat[][src]

Modules

+
options

Structs

+
Stater

Enums

+
OutputType
Token

Constants

+
F_ALTER
F_GROUP
F_LEFT
F_SIGN
F_SPACE
F_ZERO

Traits

+
ScanUtil

Functions

+
group_num
uu_app
uumain
\ No newline at end of file diff --git a/uu_stat/options/index.html b/uu_stat/options/index.html new file mode 100644 index 000000000..cacd28818 --- /dev/null +++ b/uu_stat/options/index.html @@ -0,0 +1,4 @@ +uu_stat::options - Rust + +

Module uu_stat::options[][src]

Statics

+
DEREFERENCE
FILE_SYSTEM
FORMAT
PRINTF
TERSE
\ No newline at end of file diff --git a/uu_stat/options/sidebar-items.js b/uu_stat/options/sidebar-items.js new file mode 100644 index 000000000..921447529 --- /dev/null +++ b/uu_stat/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["DEREFERENCE",""],["FILE_SYSTEM",""],["FORMAT",""],["PRINTF",""],["TERSE",""]]}); \ No newline at end of file diff --git a/uu_stat/options/static.DEREFERENCE.html b/uu_stat/options/static.DEREFERENCE.html new file mode 100644 index 000000000..4c53d5c51 --- /dev/null +++ b/uu_stat/options/static.DEREFERENCE.html @@ -0,0 +1,3 @@ +DEREFERENCE in uu_stat::options - Rust + +

Static uu_stat::options::DEREFERENCE[][src]

pub static DEREFERENCE: &str
\ No newline at end of file diff --git a/uu_stat/options/static.FILE_SYSTEM.html b/uu_stat/options/static.FILE_SYSTEM.html new file mode 100644 index 000000000..dea8959e8 --- /dev/null +++ b/uu_stat/options/static.FILE_SYSTEM.html @@ -0,0 +1,3 @@ +FILE_SYSTEM in uu_stat::options - Rust + +

Static uu_stat::options::FILE_SYSTEM[][src]

pub static FILE_SYSTEM: &str
\ No newline at end of file diff --git a/uu_stat/options/static.FORMAT.html b/uu_stat/options/static.FORMAT.html new file mode 100644 index 000000000..7aa79ea16 --- /dev/null +++ b/uu_stat/options/static.FORMAT.html @@ -0,0 +1,3 @@ +FORMAT in uu_stat::options - Rust + +

Static uu_stat::options::FORMAT[][src]

pub static FORMAT: &str
\ No newline at end of file diff --git a/uu_stat/options/static.PRINTF.html b/uu_stat/options/static.PRINTF.html new file mode 100644 index 000000000..b7acf81a3 --- /dev/null +++ b/uu_stat/options/static.PRINTF.html @@ -0,0 +1,3 @@ +PRINTF in uu_stat::options - Rust + +

Static uu_stat::options::PRINTF[][src]

pub static PRINTF: &str
\ No newline at end of file diff --git a/uu_stat/options/static.TERSE.html b/uu_stat/options/static.TERSE.html new file mode 100644 index 000000000..2470de3a1 --- /dev/null +++ b/uu_stat/options/static.TERSE.html @@ -0,0 +1,3 @@ +TERSE in uu_stat::options - Rust + +

Static uu_stat::options::TERSE[][src]

pub static TERSE: &str
\ No newline at end of file diff --git a/uu_stat/sidebar-items.js b/uu_stat/sidebar-items.js new file mode 100644 index 000000000..379c743f7 --- /dev/null +++ b/uu_stat/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["F_ALTER",""],["F_GROUP",""],["F_LEFT",""],["F_SIGN",""],["F_SPACE",""],["F_ZERO",""]],"enum":[["OutputType",""],["Token",""]],"fn":[["group_num",""],["uu_app",""],["uumain",""]],"mod":[["options",""]],"struct":[["Stater",""]],"trait":[["ScanUtil",""]]}); \ No newline at end of file diff --git a/uu_stat/struct.Stater.html b/uu_stat/struct.Stater.html new file mode 100644 index 000000000..7868b8f6c --- /dev/null +++ b/uu_stat/struct.Stater.html @@ -0,0 +1,12 @@ +Stater in uu_stat - Rust + +

Struct uu_stat::Stater[][src]

pub struct Stater { /* fields omitted */ }

Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_stat/trait.ScanUtil.html b/uu_stat/trait.ScanUtil.html new file mode 100644 index 000000000..97c6f911b --- /dev/null +++ b/uu_stat/trait.ScanUtil.html @@ -0,0 +1,6 @@ +ScanUtil in uu_stat - Rust + +

Trait uu_stat::ScanUtil[][src]

pub trait ScanUtil {
+    fn scan_num<F>(&self) -> Option<(F, usize)>
    where
        F: FromStr
; +
fn scan_char(&self, radix: u32) -> Option<(char, usize)>; +}

Required methods

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/uu_stdbuf/all.html b/uu_stdbuf/all.html new file mode 100644 index 000000000..250d2f0c9 --- /dev/null +++ b/uu_stdbuf/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_stdbuf/fn.uu_app.html b/uu_stdbuf/fn.uu_app.html new file mode 100644 index 000000000..d7b44c8fb --- /dev/null +++ b/uu_stdbuf/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_stdbuf - Rust + +

Function uu_stdbuf::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_stdbuf/fn.uumain.html b/uu_stdbuf/fn.uumain.html new file mode 100644 index 000000000..24c4a1c5f --- /dev/null +++ b/uu_stdbuf/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_stdbuf - Rust + +

Function uu_stdbuf::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_stdbuf/index.html b/uu_stdbuf/index.html new file mode 100644 index 000000000..3643ce9c6 --- /dev/null +++ b/uu_stdbuf/index.html @@ -0,0 +1,4 @@ +uu_stdbuf - Rust + +

Crate uu_stdbuf[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_stdbuf/sidebar-items.js b/uu_stdbuf/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_stdbuf/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_sum/all.html b/uu_sum/all.html new file mode 100644 index 000000000..c6b66995f --- /dev/null +++ b/uu_sum/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_sum/fn.uu_app.html b/uu_sum/fn.uu_app.html new file mode 100644 index 000000000..c7222056f --- /dev/null +++ b/uu_sum/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_sum - Rust + +

Function uu_sum::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_sum/fn.uumain.html b/uu_sum/fn.uumain.html new file mode 100644 index 000000000..44b59bb0c --- /dev/null +++ b/uu_sum/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_sum - Rust + +

Function uu_sum::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_sum/index.html b/uu_sum/index.html new file mode 100644 index 000000000..43fab6a6a --- /dev/null +++ b/uu_sum/index.html @@ -0,0 +1,4 @@ +uu_sum - Rust + +

Crate uu_sum[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_sum/sidebar-items.js b/uu_sum/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_sum/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_sync/all.html b/uu_sync/all.html new file mode 100644 index 000000000..bc80ff5a9 --- /dev/null +++ b/uu_sync/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_sync/fn.uu_app.html b/uu_sync/fn.uu_app.html new file mode 100644 index 000000000..5ab66106c --- /dev/null +++ b/uu_sync/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_sync - Rust + +

Function uu_sync::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_sync/fn.uumain.html b/uu_sync/fn.uumain.html new file mode 100644 index 000000000..d70166982 --- /dev/null +++ b/uu_sync/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_sync - Rust + +

Function uu_sync::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_sync/index.html b/uu_sync/index.html new file mode 100644 index 000000000..7a720f9fd --- /dev/null +++ b/uu_sync/index.html @@ -0,0 +1,5 @@ +uu_sync - Rust + +

Crate uu_sync[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_sync/options/index.html b/uu_sync/options/index.html new file mode 100644 index 000000000..5dde4f7fe --- /dev/null +++ b/uu_sync/options/index.html @@ -0,0 +1,4 @@ +uu_sync::options - Rust + +

Module uu_sync::options[][src]

Statics

+
DATA
FILE_SYSTEM
\ No newline at end of file diff --git a/uu_sync/options/sidebar-items.js b/uu_sync/options/sidebar-items.js new file mode 100644 index 000000000..697900d93 --- /dev/null +++ b/uu_sync/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["DATA",""],["FILE_SYSTEM",""]]}); \ No newline at end of file diff --git a/uu_sync/options/static.DATA.html b/uu_sync/options/static.DATA.html new file mode 100644 index 000000000..1ee08ed11 --- /dev/null +++ b/uu_sync/options/static.DATA.html @@ -0,0 +1,3 @@ +DATA in uu_sync::options - Rust + +

Static uu_sync::options::DATA[][src]

pub static DATA: &str
\ No newline at end of file diff --git a/uu_sync/options/static.FILE_SYSTEM.html b/uu_sync/options/static.FILE_SYSTEM.html new file mode 100644 index 000000000..d84c24cac --- /dev/null +++ b/uu_sync/options/static.FILE_SYSTEM.html @@ -0,0 +1,3 @@ +FILE_SYSTEM in uu_sync::options - Rust + +

Static uu_sync::options::FILE_SYSTEM[][src]

pub static FILE_SYSTEM: &str
\ No newline at end of file diff --git a/uu_sync/sidebar-items.js b/uu_sync/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_sync/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_tac/all.html b/uu_tac/all.html new file mode 100644 index 000000000..355829def --- /dev/null +++ b/uu_tac/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_tac/fn.uu_app.html b/uu_tac/fn.uu_app.html new file mode 100644 index 000000000..c38690c7d --- /dev/null +++ b/uu_tac/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_tac - Rust + +

Function uu_tac::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_tac/fn.uumain.html b/uu_tac/fn.uumain.html new file mode 100644 index 000000000..b1c55e28b --- /dev/null +++ b/uu_tac/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_tac - Rust + +

Function uu_tac::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_tac/index.html b/uu_tac/index.html new file mode 100644 index 000000000..6013d3f7a --- /dev/null +++ b/uu_tac/index.html @@ -0,0 +1,4 @@ +uu_tac - Rust + +

Crate uu_tac[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_tac/sidebar-items.js b/uu_tac/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_tac/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_tail/all.html b/uu_tail/all.html new file mode 100644 index 000000000..dcb0046bf --- /dev/null +++ b/uu_tail/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_tail/fn.uu_app.html b/uu_tail/fn.uu_app.html new file mode 100644 index 000000000..991331678 --- /dev/null +++ b/uu_tail/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_tail - Rust + +

Function uu_tail::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_tail/fn.uumain.html b/uu_tail/fn.uumain.html new file mode 100644 index 000000000..115d3dfa2 --- /dev/null +++ b/uu_tail/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_tail - Rust + +

Function uu_tail::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_tail/index.html b/uu_tail/index.html new file mode 100644 index 000000000..4f07e7060 --- /dev/null +++ b/uu_tail/index.html @@ -0,0 +1,5 @@ +uu_tail - Rust + +

Crate uu_tail[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_tail/options/index.html b/uu_tail/options/index.html new file mode 100644 index 000000000..f184241dd --- /dev/null +++ b/uu_tail/options/index.html @@ -0,0 +1,5 @@ +uu_tail::options - Rust + +

Module uu_tail::options[][src]

Modules

+
verbosity

Statics

+
ARG_FILES
BYTES
FOLLOW
LINES
PID
SLEEP_INT
ZERO_TERM
\ No newline at end of file diff --git a/uu_tail/options/sidebar-items.js b/uu_tail/options/sidebar-items.js new file mode 100644 index 000000000..570351d82 --- /dev/null +++ b/uu_tail/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["verbosity",""]],"static":[["ARG_FILES",""],["BYTES",""],["FOLLOW",""],["LINES",""],["PID",""],["SLEEP_INT",""],["ZERO_TERM",""]]}); \ No newline at end of file diff --git a/uu_tail/options/static.ARG_FILES.html b/uu_tail/options/static.ARG_FILES.html new file mode 100644 index 000000000..f66e3a8a8 --- /dev/null +++ b/uu_tail/options/static.ARG_FILES.html @@ -0,0 +1,3 @@ +ARG_FILES in uu_tail::options - Rust + +

Static uu_tail::options::ARG_FILES[][src]

pub static ARG_FILES: &str
\ No newline at end of file diff --git a/uu_tail/options/static.BYTES.html b/uu_tail/options/static.BYTES.html new file mode 100644 index 000000000..8e9570812 --- /dev/null +++ b/uu_tail/options/static.BYTES.html @@ -0,0 +1,3 @@ +BYTES in uu_tail::options - Rust + +

Static uu_tail::options::BYTES[][src]

pub static BYTES: &str
\ No newline at end of file diff --git a/uu_tail/options/static.FOLLOW.html b/uu_tail/options/static.FOLLOW.html new file mode 100644 index 000000000..d39e9836e --- /dev/null +++ b/uu_tail/options/static.FOLLOW.html @@ -0,0 +1,3 @@ +FOLLOW in uu_tail::options - Rust + +

Static uu_tail::options::FOLLOW[][src]

pub static FOLLOW: &str
\ No newline at end of file diff --git a/uu_tail/options/static.LINES.html b/uu_tail/options/static.LINES.html new file mode 100644 index 000000000..ee6c204ec --- /dev/null +++ b/uu_tail/options/static.LINES.html @@ -0,0 +1,3 @@ +LINES in uu_tail::options - Rust + +

Static uu_tail::options::LINES[][src]

pub static LINES: &str
\ No newline at end of file diff --git a/uu_tail/options/static.PID.html b/uu_tail/options/static.PID.html new file mode 100644 index 000000000..5c5e838f8 --- /dev/null +++ b/uu_tail/options/static.PID.html @@ -0,0 +1,3 @@ +PID in uu_tail::options - Rust + +

Static uu_tail::options::PID[][src]

pub static PID: &str
\ No newline at end of file diff --git a/uu_tail/options/static.SLEEP_INT.html b/uu_tail/options/static.SLEEP_INT.html new file mode 100644 index 000000000..60a4459a2 --- /dev/null +++ b/uu_tail/options/static.SLEEP_INT.html @@ -0,0 +1,3 @@ +SLEEP_INT in uu_tail::options - Rust + +

Static uu_tail::options::SLEEP_INT[][src]

pub static SLEEP_INT: &str
\ No newline at end of file diff --git a/uu_tail/options/static.ZERO_TERM.html b/uu_tail/options/static.ZERO_TERM.html new file mode 100644 index 000000000..49cd775de --- /dev/null +++ b/uu_tail/options/static.ZERO_TERM.html @@ -0,0 +1,3 @@ +ZERO_TERM in uu_tail::options - Rust + +

Static uu_tail::options::ZERO_TERM[][src]

pub static ZERO_TERM: &str
\ No newline at end of file diff --git a/uu_tail/options/verbosity/index.html b/uu_tail/options/verbosity/index.html new file mode 100644 index 000000000..e88f2fe59 --- /dev/null +++ b/uu_tail/options/verbosity/index.html @@ -0,0 +1,4 @@ +uu_tail::options::verbosity - Rust + +

Module uu_tail::options::verbosity[][src]

Statics

+
QUIET
VERBOSE
\ No newline at end of file diff --git a/uu_tail/options/verbosity/sidebar-items.js b/uu_tail/options/verbosity/sidebar-items.js new file mode 100644 index 000000000..b8ce4594a --- /dev/null +++ b/uu_tail/options/verbosity/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["QUIET",""],["VERBOSE",""]]}); \ No newline at end of file diff --git a/uu_tail/options/verbosity/static.QUIET.html b/uu_tail/options/verbosity/static.QUIET.html new file mode 100644 index 000000000..f35274913 --- /dev/null +++ b/uu_tail/options/verbosity/static.QUIET.html @@ -0,0 +1,3 @@ +QUIET in uu_tail::options::verbosity - Rust + +

Static uu_tail::options::verbosity::QUIET[][src]

pub static QUIET: &str
\ No newline at end of file diff --git a/uu_tail/options/verbosity/static.VERBOSE.html b/uu_tail/options/verbosity/static.VERBOSE.html new file mode 100644 index 000000000..d794e1b3c --- /dev/null +++ b/uu_tail/options/verbosity/static.VERBOSE.html @@ -0,0 +1,3 @@ +VERBOSE in uu_tail::options::verbosity - Rust + +

Static uu_tail::options::verbosity::VERBOSE[][src]

pub static VERBOSE: &str
\ No newline at end of file diff --git a/uu_tail/sidebar-items.js b/uu_tail/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_tail/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_tee/all.html b/uu_tee/all.html new file mode 100644 index 000000000..dfecf2e5c --- /dev/null +++ b/uu_tee/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_tee/fn.uu_app.html b/uu_tee/fn.uu_app.html new file mode 100644 index 000000000..d8af031c1 --- /dev/null +++ b/uu_tee/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_tee - Rust + +

Function uu_tee::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_tee/fn.uumain.html b/uu_tee/fn.uumain.html new file mode 100644 index 000000000..7d577526c --- /dev/null +++ b/uu_tee/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_tee - Rust + +

Function uu_tee::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_tee/index.html b/uu_tee/index.html new file mode 100644 index 000000000..d3f0aa03b --- /dev/null +++ b/uu_tee/index.html @@ -0,0 +1,4 @@ +uu_tee - Rust + +

Crate uu_tee[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_tee/sidebar-items.js b/uu_tee/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_tee/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_test/all.html b/uu_test/all.html new file mode 100644 index 000000000..c45153f13 --- /dev/null +++ b/uu_test/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_test/fn.uu_app.html b/uu_test/fn.uu_app.html new file mode 100644 index 000000000..4e81cc436 --- /dev/null +++ b/uu_test/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_test - Rust + +

Function uu_test::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_test/fn.uumain.html b/uu_test/fn.uumain.html new file mode 100644 index 000000000..84f9e3c42 --- /dev/null +++ b/uu_test/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_test - Rust + +

Function uu_test::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_test/index.html b/uu_test/index.html new file mode 100644 index 000000000..4d2f16513 --- /dev/null +++ b/uu_test/index.html @@ -0,0 +1,4 @@ +uu_test - Rust + +

Crate uu_test[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_test/sidebar-items.js b/uu_test/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_test/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_timeout/all.html b/uu_timeout/all.html new file mode 100644 index 000000000..a3f09d811 --- /dev/null +++ b/uu_timeout/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_timeout/fn.uu_app.html b/uu_timeout/fn.uu_app.html new file mode 100644 index 000000000..e0cc57449 --- /dev/null +++ b/uu_timeout/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_timeout - Rust + +

Function uu_timeout::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_timeout/fn.uumain.html b/uu_timeout/fn.uumain.html new file mode 100644 index 000000000..a154aeed0 --- /dev/null +++ b/uu_timeout/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_timeout - Rust + +

Function uu_timeout::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_timeout/index.html b/uu_timeout/index.html new file mode 100644 index 000000000..458c3aa83 --- /dev/null +++ b/uu_timeout/index.html @@ -0,0 +1,5 @@ +uu_timeout - Rust + +

Crate uu_timeout[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_timeout/options/index.html b/uu_timeout/options/index.html new file mode 100644 index 000000000..e300219ab --- /dev/null +++ b/uu_timeout/options/index.html @@ -0,0 +1,4 @@ +uu_timeout::options - Rust + +

Module uu_timeout::options[][src]

Statics

+
COMMAND
DURATION
FOREGROUND
KILL_AFTER
PRESERVE_STATUS
SIGNAL
VERBOSE
\ No newline at end of file diff --git a/uu_timeout/options/sidebar-items.js b/uu_timeout/options/sidebar-items.js new file mode 100644 index 000000000..0e0f4b1fb --- /dev/null +++ b/uu_timeout/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["COMMAND",""],["DURATION",""],["FOREGROUND",""],["KILL_AFTER",""],["PRESERVE_STATUS",""],["SIGNAL",""],["VERBOSE",""]]}); \ No newline at end of file diff --git a/uu_timeout/options/static.COMMAND.html b/uu_timeout/options/static.COMMAND.html new file mode 100644 index 000000000..7a1872dd9 --- /dev/null +++ b/uu_timeout/options/static.COMMAND.html @@ -0,0 +1,3 @@ +COMMAND in uu_timeout::options - Rust + +

Static uu_timeout::options::COMMAND[][src]

pub static COMMAND: &str
\ No newline at end of file diff --git a/uu_timeout/options/static.DURATION.html b/uu_timeout/options/static.DURATION.html new file mode 100644 index 000000000..b703eb5c7 --- /dev/null +++ b/uu_timeout/options/static.DURATION.html @@ -0,0 +1,3 @@ +DURATION in uu_timeout::options - Rust + +

Static uu_timeout::options::DURATION[][src]

pub static DURATION: &str
\ No newline at end of file diff --git a/uu_timeout/options/static.FOREGROUND.html b/uu_timeout/options/static.FOREGROUND.html new file mode 100644 index 000000000..90a817265 --- /dev/null +++ b/uu_timeout/options/static.FOREGROUND.html @@ -0,0 +1,3 @@ +FOREGROUND in uu_timeout::options - Rust + +

Static uu_timeout::options::FOREGROUND[][src]

pub static FOREGROUND: &str
\ No newline at end of file diff --git a/uu_timeout/options/static.KILL_AFTER.html b/uu_timeout/options/static.KILL_AFTER.html new file mode 100644 index 000000000..125ae6eba --- /dev/null +++ b/uu_timeout/options/static.KILL_AFTER.html @@ -0,0 +1,3 @@ +KILL_AFTER in uu_timeout::options - Rust + +

Static uu_timeout::options::KILL_AFTER[][src]

pub static KILL_AFTER: &str
\ No newline at end of file diff --git a/uu_timeout/options/static.PRESERVE_STATUS.html b/uu_timeout/options/static.PRESERVE_STATUS.html new file mode 100644 index 000000000..1d0dd113c --- /dev/null +++ b/uu_timeout/options/static.PRESERVE_STATUS.html @@ -0,0 +1,3 @@ +PRESERVE_STATUS in uu_timeout::options - Rust + +

Static uu_timeout::options::PRESERVE_STATUS[][src]

pub static PRESERVE_STATUS: &str
\ No newline at end of file diff --git a/uu_timeout/options/static.SIGNAL.html b/uu_timeout/options/static.SIGNAL.html new file mode 100644 index 000000000..84c261dc1 --- /dev/null +++ b/uu_timeout/options/static.SIGNAL.html @@ -0,0 +1,3 @@ +SIGNAL in uu_timeout::options - Rust + +

Static uu_timeout::options::SIGNAL[][src]

pub static SIGNAL: &str
\ No newline at end of file diff --git a/uu_timeout/options/static.VERBOSE.html b/uu_timeout/options/static.VERBOSE.html new file mode 100644 index 000000000..cdeb0a266 --- /dev/null +++ b/uu_timeout/options/static.VERBOSE.html @@ -0,0 +1,3 @@ +VERBOSE in uu_timeout::options - Rust + +

Static uu_timeout::options::VERBOSE[][src]

pub static VERBOSE: &str
\ No newline at end of file diff --git a/uu_timeout/sidebar-items.js b/uu_timeout/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_timeout/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_touch/all.html b/uu_touch/all.html new file mode 100644 index 000000000..57ccb7b2e --- /dev/null +++ b/uu_touch/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_touch/fn.uu_app.html b/uu_touch/fn.uu_app.html new file mode 100644 index 000000000..fd0577ea3 --- /dev/null +++ b/uu_touch/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_touch - Rust + +

Function uu_touch::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_touch/fn.uumain.html b/uu_touch/fn.uumain.html new file mode 100644 index 000000000..285d263b3 --- /dev/null +++ b/uu_touch/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_touch - Rust + +

Function uu_touch::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_touch/index.html b/uu_touch/index.html new file mode 100644 index 000000000..97744b5ac --- /dev/null +++ b/uu_touch/index.html @@ -0,0 +1,6 @@ +uu_touch - Rust + +

Crate uu_touch[][src]

Re-exports

+
pub extern crate filetime;

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_touch/options/index.html b/uu_touch/options/index.html new file mode 100644 index 000000000..f283ca765 --- /dev/null +++ b/uu_touch/options/index.html @@ -0,0 +1,5 @@ +uu_touch::options - Rust + +

Module uu_touch::options[][src]

Modules

+
sources

Statics

+
ACCESS
MODIFICATION
NO_CREATE
NO_DEREF
SOURCES
TIME
\ No newline at end of file diff --git a/uu_touch/options/sidebar-items.js b/uu_touch/options/sidebar-items.js new file mode 100644 index 000000000..c0dbb5503 --- /dev/null +++ b/uu_touch/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"mod":[["sources",""]],"static":[["ACCESS",""],["MODIFICATION",""],["NO_CREATE",""],["NO_DEREF",""],["SOURCES",""],["TIME",""]]}); \ No newline at end of file diff --git a/uu_touch/options/sources/index.html b/uu_touch/options/sources/index.html new file mode 100644 index 000000000..0aadca62d --- /dev/null +++ b/uu_touch/options/sources/index.html @@ -0,0 +1,4 @@ +uu_touch::options::sources - Rust + +

Module uu_touch::options::sources[][src]

Statics

+
CURRENT
DATE
REFERENCE
\ No newline at end of file diff --git a/uu_touch/options/sources/sidebar-items.js b/uu_touch/options/sources/sidebar-items.js new file mode 100644 index 000000000..0fca0ad88 --- /dev/null +++ b/uu_touch/options/sources/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["CURRENT",""],["DATE",""],["REFERENCE",""]]}); \ No newline at end of file diff --git a/uu_touch/options/sources/static.CURRENT.html b/uu_touch/options/sources/static.CURRENT.html new file mode 100644 index 000000000..e312f55a8 --- /dev/null +++ b/uu_touch/options/sources/static.CURRENT.html @@ -0,0 +1,3 @@ +CURRENT in uu_touch::options::sources - Rust + +

Static uu_touch::options::sources::CURRENT[][src]

pub static CURRENT: &str
\ No newline at end of file diff --git a/uu_touch/options/sources/static.DATE.html b/uu_touch/options/sources/static.DATE.html new file mode 100644 index 000000000..7fc093bb7 --- /dev/null +++ b/uu_touch/options/sources/static.DATE.html @@ -0,0 +1,3 @@ +DATE in uu_touch::options::sources - Rust + +

Static uu_touch::options::sources::DATE[][src]

pub static DATE: &str
\ No newline at end of file diff --git a/uu_touch/options/sources/static.REFERENCE.html b/uu_touch/options/sources/static.REFERENCE.html new file mode 100644 index 000000000..884554bbc --- /dev/null +++ b/uu_touch/options/sources/static.REFERENCE.html @@ -0,0 +1,3 @@ +REFERENCE in uu_touch::options::sources - Rust + +

Static uu_touch::options::sources::REFERENCE[][src]

pub static REFERENCE: &str
\ No newline at end of file diff --git a/uu_touch/options/static.ACCESS.html b/uu_touch/options/static.ACCESS.html new file mode 100644 index 000000000..2079011ce --- /dev/null +++ b/uu_touch/options/static.ACCESS.html @@ -0,0 +1,3 @@ +ACCESS in uu_touch::options - Rust + +

Static uu_touch::options::ACCESS[][src]

pub static ACCESS: &str
\ No newline at end of file diff --git a/uu_touch/options/static.MODIFICATION.html b/uu_touch/options/static.MODIFICATION.html new file mode 100644 index 000000000..94b1fdf55 --- /dev/null +++ b/uu_touch/options/static.MODIFICATION.html @@ -0,0 +1,3 @@ +MODIFICATION in uu_touch::options - Rust + +

Static uu_touch::options::MODIFICATION[][src]

pub static MODIFICATION: &str
\ No newline at end of file diff --git a/uu_touch/options/static.NO_CREATE.html b/uu_touch/options/static.NO_CREATE.html new file mode 100644 index 000000000..66807c248 --- /dev/null +++ b/uu_touch/options/static.NO_CREATE.html @@ -0,0 +1,3 @@ +NO_CREATE in uu_touch::options - Rust + +

Static uu_touch::options::NO_CREATE[][src]

pub static NO_CREATE: &str
\ No newline at end of file diff --git a/uu_touch/options/static.NO_DEREF.html b/uu_touch/options/static.NO_DEREF.html new file mode 100644 index 000000000..49465a864 --- /dev/null +++ b/uu_touch/options/static.NO_DEREF.html @@ -0,0 +1,3 @@ +NO_DEREF in uu_touch::options - Rust + +

Static uu_touch::options::NO_DEREF[][src]

pub static NO_DEREF: &str
\ No newline at end of file diff --git a/uu_touch/options/static.SOURCES.html b/uu_touch/options/static.SOURCES.html new file mode 100644 index 000000000..ca937c620 --- /dev/null +++ b/uu_touch/options/static.SOURCES.html @@ -0,0 +1,3 @@ +SOURCES in uu_touch::options - Rust + +

Static uu_touch::options::SOURCES[][src]

pub static SOURCES: &str
\ No newline at end of file diff --git a/uu_touch/options/static.TIME.html b/uu_touch/options/static.TIME.html new file mode 100644 index 000000000..32b60b5ef --- /dev/null +++ b/uu_touch/options/static.TIME.html @@ -0,0 +1,3 @@ +TIME in uu_touch::options - Rust + +

Static uu_touch::options::TIME[][src]

pub static TIME: &str
\ No newline at end of file diff --git a/uu_touch/sidebar-items.js b/uu_touch/sidebar-items.js new file mode 100644 index 000000000..f16c6cf9a --- /dev/null +++ b/uu_touch/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"externcrate":[["filetime",""]],"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_tr/all.html b/uu_tr/all.html new file mode 100644 index 000000000..66f291024 --- /dev/null +++ b/uu_tr/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_tr/fn.uu_app.html b/uu_tr/fn.uu_app.html new file mode 100644 index 000000000..f221a6276 --- /dev/null +++ b/uu_tr/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_tr - Rust + +

Function uu_tr::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_tr/fn.uumain.html b/uu_tr/fn.uumain.html new file mode 100644 index 000000000..0e3fd45d6 --- /dev/null +++ b/uu_tr/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_tr - Rust + +

Function uu_tr::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_tr/index.html b/uu_tr/index.html new file mode 100644 index 000000000..6b8497ddd --- /dev/null +++ b/uu_tr/index.html @@ -0,0 +1,4 @@ +uu_tr - Rust + +

Crate uu_tr[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_tr/sidebar-items.js b/uu_tr/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_tr/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_true/all.html b/uu_true/all.html new file mode 100644 index 000000000..f2ff14af0 --- /dev/null +++ b/uu_true/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_true/fn.uu_app.html b/uu_true/fn.uu_app.html new file mode 100644 index 000000000..dd6e649ed --- /dev/null +++ b/uu_true/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_true - Rust + +

Function uu_true::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_true/fn.uumain.html b/uu_true/fn.uumain.html new file mode 100644 index 000000000..e45011e75 --- /dev/null +++ b/uu_true/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_true - Rust + +

Function uu_true::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_true/index.html b/uu_true/index.html new file mode 100644 index 000000000..ffd82dcb8 --- /dev/null +++ b/uu_true/index.html @@ -0,0 +1,4 @@ +uu_true - Rust + +

Crate uu_true[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_true/sidebar-items.js b/uu_true/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_true/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_truncate/all.html b/uu_truncate/all.html new file mode 100644 index 000000000..af0bda255 --- /dev/null +++ b/uu_truncate/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_truncate/fn.uu_app.html b/uu_truncate/fn.uu_app.html new file mode 100644 index 000000000..517128005 --- /dev/null +++ b/uu_truncate/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_truncate - Rust + +

Function uu_truncate::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_truncate/fn.uumain.html b/uu_truncate/fn.uumain.html new file mode 100644 index 000000000..66022b7a2 --- /dev/null +++ b/uu_truncate/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_truncate - Rust + +

Function uu_truncate::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_truncate/index.html b/uu_truncate/index.html new file mode 100644 index 000000000..3da2ab894 --- /dev/null +++ b/uu_truncate/index.html @@ -0,0 +1,5 @@ +uu_truncate - Rust + +

Crate uu_truncate[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_truncate/options/index.html b/uu_truncate/options/index.html new file mode 100644 index 000000000..2089d7620 --- /dev/null +++ b/uu_truncate/options/index.html @@ -0,0 +1,4 @@ +uu_truncate::options - Rust + +

Module uu_truncate::options[][src]

Statics

+
ARG_FILES
IO_BLOCKS
NO_CREATE
REFERENCE
SIZE
\ No newline at end of file diff --git a/uu_truncate/options/sidebar-items.js b/uu_truncate/options/sidebar-items.js new file mode 100644 index 000000000..298f8a00b --- /dev/null +++ b/uu_truncate/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ARG_FILES",""],["IO_BLOCKS",""],["NO_CREATE",""],["REFERENCE",""],["SIZE",""]]}); \ No newline at end of file diff --git a/uu_truncate/options/static.ARG_FILES.html b/uu_truncate/options/static.ARG_FILES.html new file mode 100644 index 000000000..7e44e0a61 --- /dev/null +++ b/uu_truncate/options/static.ARG_FILES.html @@ -0,0 +1,3 @@ +ARG_FILES in uu_truncate::options - Rust + +

Static uu_truncate::options::ARG_FILES[][src]

pub static ARG_FILES: &str
\ No newline at end of file diff --git a/uu_truncate/options/static.IO_BLOCKS.html b/uu_truncate/options/static.IO_BLOCKS.html new file mode 100644 index 000000000..e2fe861bc --- /dev/null +++ b/uu_truncate/options/static.IO_BLOCKS.html @@ -0,0 +1,3 @@ +IO_BLOCKS in uu_truncate::options - Rust + +

Static uu_truncate::options::IO_BLOCKS[][src]

pub static IO_BLOCKS: &str
\ No newline at end of file diff --git a/uu_truncate/options/static.NO_CREATE.html b/uu_truncate/options/static.NO_CREATE.html new file mode 100644 index 000000000..8adab766b --- /dev/null +++ b/uu_truncate/options/static.NO_CREATE.html @@ -0,0 +1,3 @@ +NO_CREATE in uu_truncate::options - Rust + +

Static uu_truncate::options::NO_CREATE[][src]

pub static NO_CREATE: &str
\ No newline at end of file diff --git a/uu_truncate/options/static.REFERENCE.html b/uu_truncate/options/static.REFERENCE.html new file mode 100644 index 000000000..25747a490 --- /dev/null +++ b/uu_truncate/options/static.REFERENCE.html @@ -0,0 +1,3 @@ +REFERENCE in uu_truncate::options - Rust + +

Static uu_truncate::options::REFERENCE[][src]

pub static REFERENCE: &str
\ No newline at end of file diff --git a/uu_truncate/options/static.SIZE.html b/uu_truncate/options/static.SIZE.html new file mode 100644 index 000000000..e10f6bc84 --- /dev/null +++ b/uu_truncate/options/static.SIZE.html @@ -0,0 +1,3 @@ +SIZE in uu_truncate::options - Rust + +

Static uu_truncate::options::SIZE[][src]

pub static SIZE: &str
\ No newline at end of file diff --git a/uu_truncate/sidebar-items.js b/uu_truncate/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_truncate/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_tsort/all.html b/uu_tsort/all.html new file mode 100644 index 000000000..a03ab5fa0 --- /dev/null +++ b/uu_tsort/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_tsort/fn.uu_app.html b/uu_tsort/fn.uu_app.html new file mode 100644 index 000000000..0725808c2 --- /dev/null +++ b/uu_tsort/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_tsort - Rust + +

Function uu_tsort::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_tsort/fn.uumain.html b/uu_tsort/fn.uumain.html new file mode 100644 index 000000000..9667a4d85 --- /dev/null +++ b/uu_tsort/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_tsort - Rust + +

Function uu_tsort::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_tsort/index.html b/uu_tsort/index.html new file mode 100644 index 000000000..70d2a10be --- /dev/null +++ b/uu_tsort/index.html @@ -0,0 +1,4 @@ +uu_tsort - Rust + +

Crate uu_tsort[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_tsort/sidebar-items.js b/uu_tsort/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_tsort/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_tty/all.html b/uu_tty/all.html new file mode 100644 index 000000000..d5fa5699e --- /dev/null +++ b/uu_tty/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_tty/fn.uu_app.html b/uu_tty/fn.uu_app.html new file mode 100644 index 000000000..343e1187a --- /dev/null +++ b/uu_tty/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_tty - Rust + +

Function uu_tty::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_tty/fn.uumain.html b/uu_tty/fn.uumain.html new file mode 100644 index 000000000..a8f74ff43 --- /dev/null +++ b/uu_tty/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_tty - Rust + +

Function uu_tty::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_tty/index.html b/uu_tty/index.html new file mode 100644 index 000000000..37bc4eacb --- /dev/null +++ b/uu_tty/index.html @@ -0,0 +1,4 @@ +uu_tty - Rust + +

Crate uu_tty[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_tty/sidebar-items.js b/uu_tty/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_tty/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_uname/all.html b/uu_uname/all.html new file mode 100644 index 000000000..d502cd7cf --- /dev/null +++ b/uu_uname/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_uname/fn.uu_app.html b/uu_uname/fn.uu_app.html new file mode 100644 index 000000000..0079885bf --- /dev/null +++ b/uu_uname/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_uname - Rust + +

Function uu_uname::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_uname/fn.uumain.html b/uu_uname/fn.uumain.html new file mode 100644 index 000000000..2fc565a4a --- /dev/null +++ b/uu_uname/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_uname - Rust + +

Function uu_uname::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_uname/index.html b/uu_uname/index.html new file mode 100644 index 000000000..3328980d1 --- /dev/null +++ b/uu_uname/index.html @@ -0,0 +1,5 @@ +uu_uname - Rust + +

Crate uu_uname[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_uname/options/index.html b/uu_uname/options/index.html new file mode 100644 index 000000000..13ddbc006 --- /dev/null +++ b/uu_uname/options/index.html @@ -0,0 +1,4 @@ +uu_uname::options - Rust + +

Module uu_uname::options[][src]

Statics

+
ALL
HWPLATFORM
KERNELNAME
KERNELRELEASE
KERNELVERSION
MACHINE
NODENAME
OS
PROCESSOR
\ No newline at end of file diff --git a/uu_uname/options/sidebar-items.js b/uu_uname/options/sidebar-items.js new file mode 100644 index 000000000..1ef675d40 --- /dev/null +++ b/uu_uname/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ALL",""],["HWPLATFORM",""],["KERNELNAME",""],["KERNELRELEASE",""],["KERNELVERSION",""],["MACHINE",""],["NODENAME",""],["OS",""],["PROCESSOR",""]]}); \ No newline at end of file diff --git a/uu_uname/options/static.ALL.html b/uu_uname/options/static.ALL.html new file mode 100644 index 000000000..5bcb1231b --- /dev/null +++ b/uu_uname/options/static.ALL.html @@ -0,0 +1,3 @@ +ALL in uu_uname::options - Rust + +

Static uu_uname::options::ALL[][src]

pub static ALL: &str
\ No newline at end of file diff --git a/uu_uname/options/static.HWPLATFORM.html b/uu_uname/options/static.HWPLATFORM.html new file mode 100644 index 000000000..cefd93adb --- /dev/null +++ b/uu_uname/options/static.HWPLATFORM.html @@ -0,0 +1,3 @@ +HWPLATFORM in uu_uname::options - Rust + +

Static uu_uname::options::HWPLATFORM[][src]

pub static HWPLATFORM: &str
\ No newline at end of file diff --git a/uu_uname/options/static.KERNELNAME.html b/uu_uname/options/static.KERNELNAME.html new file mode 100644 index 000000000..fd78522a8 --- /dev/null +++ b/uu_uname/options/static.KERNELNAME.html @@ -0,0 +1,3 @@ +KERNELNAME in uu_uname::options - Rust + +

Static uu_uname::options::KERNELNAME[][src]

pub static KERNELNAME: &str
\ No newline at end of file diff --git a/uu_uname/options/static.KERNELRELEASE.html b/uu_uname/options/static.KERNELRELEASE.html new file mode 100644 index 000000000..4f2f4de9c --- /dev/null +++ b/uu_uname/options/static.KERNELRELEASE.html @@ -0,0 +1,3 @@ +KERNELRELEASE in uu_uname::options - Rust + +

Static uu_uname::options::KERNELRELEASE[][src]

pub static KERNELRELEASE: &str
\ No newline at end of file diff --git a/uu_uname/options/static.KERNELVERSION.html b/uu_uname/options/static.KERNELVERSION.html new file mode 100644 index 000000000..0dc710452 --- /dev/null +++ b/uu_uname/options/static.KERNELVERSION.html @@ -0,0 +1,3 @@ +KERNELVERSION in uu_uname::options - Rust + +

Static uu_uname::options::KERNELVERSION[][src]

pub static KERNELVERSION: &str
\ No newline at end of file diff --git a/uu_uname/options/static.MACHINE.html b/uu_uname/options/static.MACHINE.html new file mode 100644 index 000000000..0af46edac --- /dev/null +++ b/uu_uname/options/static.MACHINE.html @@ -0,0 +1,3 @@ +MACHINE in uu_uname::options - Rust + +

Static uu_uname::options::MACHINE[][src]

pub static MACHINE: &str
\ No newline at end of file diff --git a/uu_uname/options/static.NODENAME.html b/uu_uname/options/static.NODENAME.html new file mode 100644 index 000000000..403abcaba --- /dev/null +++ b/uu_uname/options/static.NODENAME.html @@ -0,0 +1,3 @@ +NODENAME in uu_uname::options - Rust + +

Static uu_uname::options::NODENAME[][src]

pub static NODENAME: &str
\ No newline at end of file diff --git a/uu_uname/options/static.OS.html b/uu_uname/options/static.OS.html new file mode 100644 index 000000000..644006949 --- /dev/null +++ b/uu_uname/options/static.OS.html @@ -0,0 +1,3 @@ +OS in uu_uname::options - Rust + +

Static uu_uname::options::OS[][src]

pub static OS: &str
\ No newline at end of file diff --git a/uu_uname/options/static.PROCESSOR.html b/uu_uname/options/static.PROCESSOR.html new file mode 100644 index 000000000..14a625118 --- /dev/null +++ b/uu_uname/options/static.PROCESSOR.html @@ -0,0 +1,3 @@ +PROCESSOR in uu_uname::options - Rust + +

Static uu_uname::options::PROCESSOR[][src]

pub static PROCESSOR: &str
\ No newline at end of file diff --git a/uu_uname/sidebar-items.js b/uu_uname/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_uname/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_unexpand/all.html b/uu_unexpand/all.html new file mode 100644 index 000000000..316db4c2b --- /dev/null +++ b/uu_unexpand/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_unexpand/fn.uu_app.html b/uu_unexpand/fn.uu_app.html new file mode 100644 index 000000000..99385352b --- /dev/null +++ b/uu_unexpand/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_unexpand - Rust + +

Function uu_unexpand::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_unexpand/fn.uumain.html b/uu_unexpand/fn.uumain.html new file mode 100644 index 000000000..8c171181f --- /dev/null +++ b/uu_unexpand/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_unexpand - Rust + +

Function uu_unexpand::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_unexpand/index.html b/uu_unexpand/index.html new file mode 100644 index 000000000..e95757e28 --- /dev/null +++ b/uu_unexpand/index.html @@ -0,0 +1,4 @@ +uu_unexpand - Rust + +

Crate uu_unexpand[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_unexpand/sidebar-items.js b/uu_unexpand/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_unexpand/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_uniq/all.html b/uu_uniq/all.html new file mode 100644 index 000000000..c04f50631 --- /dev/null +++ b/uu_uniq/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_uniq/fn.uu_app.html b/uu_uniq/fn.uu_app.html new file mode 100644 index 000000000..b9e9f1077 --- /dev/null +++ b/uu_uniq/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_uniq - Rust + +

Function uu_uniq::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_uniq/fn.uumain.html b/uu_uniq/fn.uumain.html new file mode 100644 index 000000000..b8d62fa7b --- /dev/null +++ b/uu_uniq/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_uniq - Rust + +

Function uu_uniq::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_uniq/index.html b/uu_uniq/index.html new file mode 100644 index 000000000..30f519df5 --- /dev/null +++ b/uu_uniq/index.html @@ -0,0 +1,5 @@ +uu_uniq - Rust + +

Crate uu_uniq[][src]

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_uniq/options/index.html b/uu_uniq/options/index.html new file mode 100644 index 000000000..46baea64c --- /dev/null +++ b/uu_uniq/options/index.html @@ -0,0 +1,4 @@ +uu_uniq::options - Rust + +

Module uu_uniq::options[][src]

Statics

+
ALL_REPEATED
CHECK_CHARS
COUNT
GROUP
IGNORE_CASE
REPEATED
SKIP_CHARS
SKIP_FIELDS
UNIQUE
ZERO_TERMINATED
\ No newline at end of file diff --git a/uu_uniq/options/sidebar-items.js b/uu_uniq/options/sidebar-items.js new file mode 100644 index 000000000..38418bbbf --- /dev/null +++ b/uu_uniq/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["ALL_REPEATED",""],["CHECK_CHARS",""],["COUNT",""],["GROUP",""],["IGNORE_CASE",""],["REPEATED",""],["SKIP_CHARS",""],["SKIP_FIELDS",""],["UNIQUE",""],["ZERO_TERMINATED",""]]}); \ No newline at end of file diff --git a/uu_uniq/options/static.ALL_REPEATED.html b/uu_uniq/options/static.ALL_REPEATED.html new file mode 100644 index 000000000..88890e8f0 --- /dev/null +++ b/uu_uniq/options/static.ALL_REPEATED.html @@ -0,0 +1,3 @@ +ALL_REPEATED in uu_uniq::options - Rust + +

Static uu_uniq::options::ALL_REPEATED[][src]

pub static ALL_REPEATED: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.CHECK_CHARS.html b/uu_uniq/options/static.CHECK_CHARS.html new file mode 100644 index 000000000..54603eb84 --- /dev/null +++ b/uu_uniq/options/static.CHECK_CHARS.html @@ -0,0 +1,3 @@ +CHECK_CHARS in uu_uniq::options - Rust + +

Static uu_uniq::options::CHECK_CHARS[][src]

pub static CHECK_CHARS: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.COUNT.html b/uu_uniq/options/static.COUNT.html new file mode 100644 index 000000000..fae37d71b --- /dev/null +++ b/uu_uniq/options/static.COUNT.html @@ -0,0 +1,3 @@ +COUNT in uu_uniq::options - Rust + +

Static uu_uniq::options::COUNT[][src]

pub static COUNT: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.GROUP.html b/uu_uniq/options/static.GROUP.html new file mode 100644 index 000000000..934413a59 --- /dev/null +++ b/uu_uniq/options/static.GROUP.html @@ -0,0 +1,3 @@ +GROUP in uu_uniq::options - Rust + +

Static uu_uniq::options::GROUP[][src]

pub static GROUP: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.IGNORE_CASE.html b/uu_uniq/options/static.IGNORE_CASE.html new file mode 100644 index 000000000..ef2babc73 --- /dev/null +++ b/uu_uniq/options/static.IGNORE_CASE.html @@ -0,0 +1,3 @@ +IGNORE_CASE in uu_uniq::options - Rust + +

Static uu_uniq::options::IGNORE_CASE[][src]

pub static IGNORE_CASE: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.REPEATED.html b/uu_uniq/options/static.REPEATED.html new file mode 100644 index 000000000..0896a2f74 --- /dev/null +++ b/uu_uniq/options/static.REPEATED.html @@ -0,0 +1,3 @@ +REPEATED in uu_uniq::options - Rust + +

Static uu_uniq::options::REPEATED[][src]

pub static REPEATED: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.SKIP_CHARS.html b/uu_uniq/options/static.SKIP_CHARS.html new file mode 100644 index 000000000..8c45bf3d7 --- /dev/null +++ b/uu_uniq/options/static.SKIP_CHARS.html @@ -0,0 +1,3 @@ +SKIP_CHARS in uu_uniq::options - Rust + +

Static uu_uniq::options::SKIP_CHARS[][src]

pub static SKIP_CHARS: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.SKIP_FIELDS.html b/uu_uniq/options/static.SKIP_FIELDS.html new file mode 100644 index 000000000..ab97fda94 --- /dev/null +++ b/uu_uniq/options/static.SKIP_FIELDS.html @@ -0,0 +1,3 @@ +SKIP_FIELDS in uu_uniq::options - Rust + +

Static uu_uniq::options::SKIP_FIELDS[][src]

pub static SKIP_FIELDS: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.UNIQUE.html b/uu_uniq/options/static.UNIQUE.html new file mode 100644 index 000000000..a840e4983 --- /dev/null +++ b/uu_uniq/options/static.UNIQUE.html @@ -0,0 +1,3 @@ +UNIQUE in uu_uniq::options - Rust + +

Static uu_uniq::options::UNIQUE[][src]

pub static UNIQUE: &str
\ No newline at end of file diff --git a/uu_uniq/options/static.ZERO_TERMINATED.html b/uu_uniq/options/static.ZERO_TERMINATED.html new file mode 100644 index 000000000..af81271ad --- /dev/null +++ b/uu_uniq/options/static.ZERO_TERMINATED.html @@ -0,0 +1,3 @@ +ZERO_TERMINATED in uu_uniq::options - Rust + +

Static uu_uniq::options::ZERO_TERMINATED[][src]

pub static ZERO_TERMINATED: &str
\ No newline at end of file diff --git a/uu_uniq/sidebar-items.js b/uu_uniq/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_uniq/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_unlink/all.html b/uu_unlink/all.html new file mode 100644 index 000000000..1f866d134 --- /dev/null +++ b/uu_unlink/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_unlink/fn.uu_app.html b/uu_unlink/fn.uu_app.html new file mode 100644 index 000000000..189e58aa7 --- /dev/null +++ b/uu_unlink/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_unlink - Rust + +

Function uu_unlink::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_unlink/fn.uumain.html b/uu_unlink/fn.uumain.html new file mode 100644 index 000000000..92fcf82c5 --- /dev/null +++ b/uu_unlink/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_unlink - Rust + +

Function uu_unlink::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_unlink/index.html b/uu_unlink/index.html new file mode 100644 index 000000000..8f1715590 --- /dev/null +++ b/uu_unlink/index.html @@ -0,0 +1,4 @@ +uu_unlink - Rust + +

Crate uu_unlink[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_unlink/sidebar-items.js b/uu_unlink/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_unlink/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_uptime/all.html b/uu_uptime/all.html new file mode 100644 index 000000000..ba95ffb6f --- /dev/null +++ b/uu_uptime/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

Statics

\ No newline at end of file diff --git a/uu_uptime/fn.uu_app.html b/uu_uptime/fn.uu_app.html new file mode 100644 index 000000000..b5dbf2fed --- /dev/null +++ b/uu_uptime/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_uptime - Rust + +

Function uu_uptime::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_uptime/fn.uumain.html b/uu_uptime/fn.uumain.html new file mode 100644 index 000000000..8667ae0fa --- /dev/null +++ b/uu_uptime/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_uptime - Rust + +

Function uu_uptime::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_uptime/index.html b/uu_uptime/index.html new file mode 100644 index 000000000..e117956a4 --- /dev/null +++ b/uu_uptime/index.html @@ -0,0 +1,6 @@ +uu_uptime - Rust + +

Crate uu_uptime[][src]

Re-exports

+
pub use uucore::libc;

Modules

+
options

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_uptime/options/index.html b/uu_uptime/options/index.html new file mode 100644 index 000000000..bbe307ad7 --- /dev/null +++ b/uu_uptime/options/index.html @@ -0,0 +1,4 @@ +uu_uptime::options - Rust + +

Module uu_uptime::options[][src]

Statics

+
SINCE
\ No newline at end of file diff --git a/uu_uptime/options/sidebar-items.js b/uu_uptime/options/sidebar-items.js new file mode 100644 index 000000000..4c84ac2c8 --- /dev/null +++ b/uu_uptime/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["SINCE",""]]}); \ No newline at end of file diff --git a/uu_uptime/options/static.SINCE.html b/uu_uptime/options/static.SINCE.html new file mode 100644 index 000000000..5283f4fa5 --- /dev/null +++ b/uu_uptime/options/static.SINCE.html @@ -0,0 +1,3 @@ +SINCE in uu_uptime::options - Rust + +

Static uu_uptime::options::SINCE[][src]

pub static SINCE: &str
\ No newline at end of file diff --git a/uu_uptime/sidebar-items.js b/uu_uptime/sidebar-items.js new file mode 100644 index 000000000..7a8cecaf3 --- /dev/null +++ b/uu_uptime/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_users/all.html b/uu_users/all.html new file mode 100644 index 000000000..578c994fd --- /dev/null +++ b/uu_users/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_users/fn.uu_app.html b/uu_users/fn.uu_app.html new file mode 100644 index 000000000..bf52c08b8 --- /dev/null +++ b/uu_users/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_users - Rust + +

Function uu_users::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_users/fn.uumain.html b/uu_users/fn.uumain.html new file mode 100644 index 000000000..fa789d80f --- /dev/null +++ b/uu_users/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_users - Rust + +

Function uu_users::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_users/index.html b/uu_users/index.html new file mode 100644 index 000000000..ae6391ce1 --- /dev/null +++ b/uu_users/index.html @@ -0,0 +1,4 @@ +uu_users - Rust + +

Crate uu_users[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_users/sidebar-items.js b/uu_users/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_users/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_wc/all.html b/uu_wc/all.html new file mode 100644 index 000000000..693ac095f --- /dev/null +++ b/uu_wc/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Enums

Functions

Statics

\ No newline at end of file diff --git a/uu_wc/enum.WcError.html b/uu_wc/enum.WcError.html new file mode 100644 index 000000000..619f32c51 --- /dev/null +++ b/uu_wc/enum.WcError.html @@ -0,0 +1,25 @@ +WcError in uu_wc - Rust + +

Enum uu_wc::WcError[][src]

pub enum WcError {
+    Io(Error),
+    IsDirectory(String),
+}

+ Variants

+
Io(Error)
IsDirectory(String)

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uu_wc/fn.uu_app.html b/uu_wc/fn.uu_app.html new file mode 100644 index 000000000..24a19d6f3 --- /dev/null +++ b/uu_wc/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_wc - Rust + +

Function uu_wc::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_wc/fn.uumain.html b/uu_wc/fn.uumain.html new file mode 100644 index 000000000..24e9a440e --- /dev/null +++ b/uu_wc/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_wc - Rust + +

Function uu_wc::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_wc/index.html b/uu_wc/index.html new file mode 100644 index 000000000..5c0e9970b --- /dev/null +++ b/uu_wc/index.html @@ -0,0 +1,6 @@ +uu_wc - Rust + +

Crate uu_wc[][src]

Modules

+
options

Enums

+
WcError

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_wc/options/index.html b/uu_wc/options/index.html new file mode 100644 index 000000000..758b186bf --- /dev/null +++ b/uu_wc/options/index.html @@ -0,0 +1,4 @@ +uu_wc::options - Rust + +

Module uu_wc::options[][src]

Statics

+
BYTES
CHAR
LINES
MAX_LINE_LENGTH
WORDS
\ No newline at end of file diff --git a/uu_wc/options/sidebar-items.js b/uu_wc/options/sidebar-items.js new file mode 100644 index 000000000..1552faad1 --- /dev/null +++ b/uu_wc/options/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"static":[["BYTES",""],["CHAR",""],["LINES",""],["MAX_LINE_LENGTH",""],["WORDS",""]]}); \ No newline at end of file diff --git a/uu_wc/options/static.BYTES.html b/uu_wc/options/static.BYTES.html new file mode 100644 index 000000000..60838154f --- /dev/null +++ b/uu_wc/options/static.BYTES.html @@ -0,0 +1,3 @@ +BYTES in uu_wc::options - Rust + +

Static uu_wc::options::BYTES[][src]

pub static BYTES: &str
\ No newline at end of file diff --git a/uu_wc/options/static.CHAR.html b/uu_wc/options/static.CHAR.html new file mode 100644 index 000000000..4ccdaefd8 --- /dev/null +++ b/uu_wc/options/static.CHAR.html @@ -0,0 +1,3 @@ +CHAR in uu_wc::options - Rust + +

Static uu_wc::options::CHAR[][src]

pub static CHAR: &str
\ No newline at end of file diff --git a/uu_wc/options/static.LINES.html b/uu_wc/options/static.LINES.html new file mode 100644 index 000000000..e091db888 --- /dev/null +++ b/uu_wc/options/static.LINES.html @@ -0,0 +1,3 @@ +LINES in uu_wc::options - Rust + +

Static uu_wc::options::LINES[][src]

pub static LINES: &str
\ No newline at end of file diff --git a/uu_wc/options/static.MAX_LINE_LENGTH.html b/uu_wc/options/static.MAX_LINE_LENGTH.html new file mode 100644 index 000000000..f173dcad5 --- /dev/null +++ b/uu_wc/options/static.MAX_LINE_LENGTH.html @@ -0,0 +1,3 @@ +MAX_LINE_LENGTH in uu_wc::options - Rust + +

Static uu_wc::options::MAX_LINE_LENGTH[][src]

pub static MAX_LINE_LENGTH: &str
\ No newline at end of file diff --git a/uu_wc/options/static.WORDS.html b/uu_wc/options/static.WORDS.html new file mode 100644 index 000000000..c37034c24 --- /dev/null +++ b/uu_wc/options/static.WORDS.html @@ -0,0 +1,3 @@ +WORDS in uu_wc::options - Rust + +

Static uu_wc::options::WORDS[][src]

pub static WORDS: &str
\ No newline at end of file diff --git a/uu_wc/sidebar-items.js b/uu_wc/sidebar-items.js new file mode 100644 index 000000000..be6cb3bf7 --- /dev/null +++ b/uu_wc/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["WcError",""]],"fn":[["uu_app",""],["uumain",""]],"mod":[["options",""]]}); \ No newline at end of file diff --git a/uu_who/all.html b/uu_who/all.html new file mode 100644 index 000000000..c0a3ca1ff --- /dev/null +++ b/uu_who/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_who/fn.uu_app.html b/uu_who/fn.uu_app.html new file mode 100644 index 000000000..9564fdae3 --- /dev/null +++ b/uu_who/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_who - Rust + +

Function uu_who::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_who/fn.uumain.html b/uu_who/fn.uumain.html new file mode 100644 index 000000000..d8c171484 --- /dev/null +++ b/uu_who/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_who - Rust + +

Function uu_who::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_who/index.html b/uu_who/index.html new file mode 100644 index 000000000..5e865d95a --- /dev/null +++ b/uu_who/index.html @@ -0,0 +1,4 @@ +uu_who - Rust + +

Crate uu_who[][src]

Functions

+
uu_app
uumain
\ No newline at end of file diff --git a/uu_who/sidebar-items.js b/uu_who/sidebar-items.js new file mode 100644 index 000000000..887ccda3b --- /dev/null +++ b/uu_who/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_whoami/all.html b/uu_whoami/all.html new file mode 100644 index 000000000..f1ec563d0 --- /dev/null +++ b/uu_whoami/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_whoami/fn.exec.html b/uu_whoami/fn.exec.html new file mode 100644 index 000000000..78eeac5ee --- /dev/null +++ b/uu_whoami/fn.exec.html @@ -0,0 +1,3 @@ +exec in uu_whoami - Rust + +

Function uu_whoami::exec[][src]

pub fn exec()
\ No newline at end of file diff --git a/uu_whoami/fn.uu_app.html b/uu_whoami/fn.uu_app.html new file mode 100644 index 000000000..450280519 --- /dev/null +++ b/uu_whoami/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_whoami - Rust + +

Function uu_whoami::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_whoami/fn.uumain.html b/uu_whoami/fn.uumain.html new file mode 100644 index 000000000..d8bfe8cc5 --- /dev/null +++ b/uu_whoami/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_whoami - Rust + +

Function uu_whoami::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_whoami/index.html b/uu_whoami/index.html new file mode 100644 index 000000000..482db4245 --- /dev/null +++ b/uu_whoami/index.html @@ -0,0 +1,4 @@ +uu_whoami - Rust + +

Crate uu_whoami[][src]

Functions

+
exec
uu_app
uumain
\ No newline at end of file diff --git a/uu_whoami/sidebar-items.js b/uu_whoami/sidebar-items.js new file mode 100644 index 000000000..f0892aeaf --- /dev/null +++ b/uu_whoami/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["exec",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uu_yes/all.html b/uu_yes/all.html new file mode 100644 index 000000000..d259ca524 --- /dev/null +++ b/uu_yes/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/uu_yes/fn.exec.html b/uu_yes/fn.exec.html new file mode 100644 index 000000000..7187ab514 --- /dev/null +++ b/uu_yes/fn.exec.html @@ -0,0 +1,3 @@ +exec in uu_yes - Rust + +

Function uu_yes::exec[][src]

pub fn exec(bytes: &[u8])
\ No newline at end of file diff --git a/uu_yes/fn.uu_app.html b/uu_yes/fn.uu_app.html new file mode 100644 index 000000000..2f6763456 --- /dev/null +++ b/uu_yes/fn.uu_app.html @@ -0,0 +1,3 @@ +uu_app in uu_yes - Rust + +

Function uu_yes::uu_app[][src]

pub fn uu_app() -> App<'static, 'static>
\ No newline at end of file diff --git a/uu_yes/fn.uumain.html b/uu_yes/fn.uumain.html new file mode 100644 index 000000000..68af2c4fc --- /dev/null +++ b/uu_yes/fn.uumain.html @@ -0,0 +1,3 @@ +uumain in uu_yes - Rust + +

Function uu_yes::uumain[][src]

pub fn uumain(args: impl Args) -> i32
\ No newline at end of file diff --git a/uu_yes/index.html b/uu_yes/index.html new file mode 100644 index 000000000..287b4b4d8 --- /dev/null +++ b/uu_yes/index.html @@ -0,0 +1,4 @@ +uu_yes - Rust + +

Crate uu_yes[][src]

Functions

+
exec
uu_app
uumain
\ No newline at end of file diff --git a/uu_yes/sidebar-items.js b/uu_yes/sidebar-items.js new file mode 100644 index 000000000..f0892aeaf --- /dev/null +++ b/uu_yes/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["exec",""],["uu_app",""],["uumain",""]]}); \ No newline at end of file diff --git a/uucore/all.html b/uucore/all.html new file mode 100644 index 000000000..a340a7db7 --- /dev/null +++ b/uucore/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Structs

Enums

Traits

Macros

Functions

Typedefs

Statics

Constants

\ No newline at end of file diff --git a/uucore/backup_control/enum.BackupMode.html b/uucore/backup_control/enum.BackupMode.html new file mode 100644 index 000000000..fab0b9f9e --- /dev/null +++ b/uucore/backup_control/enum.BackupMode.html @@ -0,0 +1,29 @@ +BackupMode in uucore::backup_control - Rust + +

Enum uucore::backup_control::BackupMode[][src]

pub enum BackupMode {
+    NoBackup,
+    SimpleBackup,
+    NumberedBackup,
+    ExistingBackup,
+}

+ Variants

+
NoBackup
SimpleBackup
NumberedBackup
ExistingBackup

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/backup_control/fn.determine_backup_mode.html b/uucore/backup_control/fn.determine_backup_mode.html new file mode 100644 index 000000000..68e91f2cc --- /dev/null +++ b/uucore/backup_control/fn.determine_backup_mode.html @@ -0,0 +1,86 @@ +determine_backup_mode in uucore::backup_control - Rust + +

Function uucore::backup_control::determine_backup_mode[][src]

pub fn determine_backup_mode(
    short_opt_present: bool,
    long_opt_present: bool,
    long_opt_value: Option<&str>
) -> Result<BackupMode, String>
Expand description

Determine the “mode” for the backup operation to perform, if any.

+

Parses the backup options according to the GNU manual, and converts +them to an instance of BackupMode for further processing.

+

For an explanation of what the arguments mean, refer to the examples below.

+

Errors

+

If an argument supplied directly to the long backup option, or read in +through the VERSION CONTROL env var is ambiguous (i.e. may resolve to +multiple backup modes) or invalid, an error is returned. The error contains +the formatted error string which may then be passed to the +show_usage_error macro.

+

Examples

+

Here’s how one would integrate the backup mode determination into an +application.

+ +
+#[macro_use]
+extern crate uucore;
+use uucore::backup_control::{self, BackupMode};
+use clap::{App, Arg};
+
+fn main() {
+    let OPT_BACKUP: &str = "backup";
+    let OPT_BACKUP_NO_ARG: &str = "b";
+    let matches = App::new("app")
+        .arg(Arg::with_name(OPT_BACKUP_NO_ARG)
+            .short(OPT_BACKUP_NO_ARG))
+        .arg(Arg::with_name(OPT_BACKUP)
+            .long(OPT_BACKUP)
+            .takes_value(true)
+            .require_equals(true)
+            .min_values(0))
+        .get_matches_from(vec![
+            "app", "-b", "--backup=t"
+        ]);
+    
+    let backup_mode = backup_control::determine_backup_mode(
+        matches.is_present(OPT_BACKUP_NO_ARG), matches.is_present(OPT_BACKUP),
+        matches.value_of(OPT_BACKUP)
+    );
+    let backup_mode = match backup_mode {
+        Err(err) => {
+            show_usage_error!("{}", err);
+            return;
+        },
+        Ok(mode) => mode,
+    };
+}
+

This example shows an ambiguous input, as ‘n’ may resolve to 4 different +backup modes.

+ +
+#[macro_use]
+extern crate uucore;
+use uucore::backup_control::{self, BackupMode};
+use clap::{crate_version, App, Arg, ArgMatches};
+
+fn main() {
+    let OPT_BACKUP: &str = "backup";
+    let OPT_BACKUP_NO_ARG: &str = "b";
+    let matches = App::new("app")
+        .arg(Arg::with_name(OPT_BACKUP_NO_ARG)
+            .short(OPT_BACKUP_NO_ARG))
+        .arg(Arg::with_name(OPT_BACKUP)
+            .long(OPT_BACKUP)
+            .takes_value(true)
+            .require_equals(true)
+            .min_values(0))
+        .get_matches_from(vec![
+            "app", "-b", "--backup=n"
+        ]);
+    
+    let backup_mode = backup_control::determine_backup_mode(
+        matches.is_present(OPT_BACKUP_NO_ARG), matches.is_present(OPT_BACKUP),
+        matches.value_of(OPT_BACKUP)
+    );
+    let backup_mode = match backup_mode {
+        Err(err) => {
+            show_usage_error!("{}", err);
+            return;
+        },
+        Ok(mode) => mode,
+    };
+}
+
\ No newline at end of file diff --git a/uucore/backup_control/fn.determine_backup_suffix.html b/uucore/backup_control/fn.determine_backup_suffix.html new file mode 100644 index 000000000..3ecd8a8db --- /dev/null +++ b/uucore/backup_control/fn.determine_backup_suffix.html @@ -0,0 +1,3 @@ +determine_backup_suffix in uucore::backup_control - Rust + +

Function uucore::backup_control::determine_backup_suffix[][src]

pub fn determine_backup_suffix(supplied_suffix: Option<&str>) -> String
\ No newline at end of file diff --git a/uucore/backup_control/fn.get_backup_path.html b/uucore/backup_control/fn.get_backup_path.html new file mode 100644 index 000000000..f62082476 --- /dev/null +++ b/uucore/backup_control/fn.get_backup_path.html @@ -0,0 +1,3 @@ +get_backup_path in uucore::backup_control - Rust + +

Function uucore::backup_control::get_backup_path[][src]

pub fn get_backup_path(
    backup_mode: BackupMode,
    backup_path: &Path,
    suffix: &str
) -> Option<PathBuf>
\ No newline at end of file diff --git a/uucore/backup_control/index.html b/uucore/backup_control/index.html new file mode 100644 index 000000000..364f90a98 --- /dev/null +++ b/uucore/backup_control/index.html @@ -0,0 +1,7 @@ +uucore::backup_control - Rust + +

Module uucore::backup_control[][src]

Enums

+
BackupMode

Statics

+
BACKUP_CONTROL_LONG_HELP
BACKUP_CONTROL_VALUES

Functions

+
determine_backup_mode

Determine the “mode” for the backup operation to perform, if any.

+
determine_backup_suffix
get_backup_path
\ No newline at end of file diff --git a/uucore/backup_control/sidebar-items.js b/uucore/backup_control/sidebar-items.js new file mode 100644 index 000000000..2d34dc002 --- /dev/null +++ b/uucore/backup_control/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["BackupMode",""]],"fn":[["determine_backup_mode","Determine the “mode” for the backup operation to perform, if any."],["determine_backup_suffix",""],["get_backup_path",""]],"static":[["BACKUP_CONTROL_LONG_HELP",""],["BACKUP_CONTROL_VALUES",""]]}); \ No newline at end of file diff --git a/uucore/backup_control/static.BACKUP_CONTROL_LONG_HELP.html b/uucore/backup_control/static.BACKUP_CONTROL_LONG_HELP.html new file mode 100644 index 000000000..cff8a28d6 --- /dev/null +++ b/uucore/backup_control/static.BACKUP_CONTROL_LONG_HELP.html @@ -0,0 +1,3 @@ +BACKUP_CONTROL_LONG_HELP in uucore::backup_control - Rust + +

Static uucore::backup_control::BACKUP_CONTROL_LONG_HELP[][src]

pub static BACKUP_CONTROL_LONG_HELP: &str
\ No newline at end of file diff --git a/uucore/backup_control/static.BACKUP_CONTROL_VALUES.html b/uucore/backup_control/static.BACKUP_CONTROL_VALUES.html new file mode 100644 index 000000000..f7c7714c2 --- /dev/null +++ b/uucore/backup_control/static.BACKUP_CONTROL_VALUES.html @@ -0,0 +1,3 @@ +BACKUP_CONTROL_VALUES in uucore::backup_control - Rust + +

Static uucore::backup_control::BACKUP_CONTROL_VALUES[][src]

pub static BACKUP_CONTROL_VALUES: &[&str]
\ No newline at end of file diff --git a/uucore/coreopts/index.html b/uucore/coreopts/index.html new file mode 100644 index 000000000..40d24ec5a --- /dev/null +++ b/uucore/coreopts/index.html @@ -0,0 +1,4 @@ +uucore::coreopts - Rust + +

Module uucore::coreopts[][src]

Structs

+
CoreOptions
HelpText
\ No newline at end of file diff --git a/uucore/coreopts/sidebar-items.js b/uucore/coreopts/sidebar-items.js new file mode 100644 index 000000000..02995baea --- /dev/null +++ b/uucore/coreopts/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["CoreOptions",""],["HelpText",""]]}); \ No newline at end of file diff --git a/uucore/coreopts/struct.CoreOptions.html b/uucore/coreopts/struct.CoreOptions.html new file mode 100644 index 000000000..dbba03646 --- /dev/null +++ b/uucore/coreopts/struct.CoreOptions.html @@ -0,0 +1,12 @@ +CoreOptions in uucore::coreopts - Rust + +

Struct uucore::coreopts::CoreOptions[][src]

pub struct CoreOptions<'a> { /* fields omitted */ }

Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/coreopts/struct.HelpText.html b/uucore/coreopts/struct.HelpText.html new file mode 100644 index 000000000..3bcb7ab4d --- /dev/null +++ b/uucore/coreopts/struct.HelpText.html @@ -0,0 +1,20 @@ +HelpText in uucore::coreopts - Rust + +

Struct uucore::coreopts::HelpText[][src]

pub struct HelpText<'a> {
+    pub name: &'a str,
+    pub version: &'a str,
+    pub syntax: &'a str,
+    pub summary: &'a str,
+    pub long_help: &'a str,
+    pub display_usage: bool,
+}

+ Fields

name: &'a strversion: &'a strsyntax: &'a strsummary: &'a strlong_help: &'a strdisplay_usage: bool

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/encoding/enum.DecodeError.html b/uucore/encoding/enum.DecodeError.html new file mode 100644 index 000000000..b70d79409 --- /dev/null +++ b/uucore/encoding/enum.DecodeError.html @@ -0,0 +1,28 @@ +DecodeError in uucore::encoding - Rust + +

Enum uucore::encoding::DecodeError[][src]

pub enum DecodeError {
+    Decode(DecodeError),
+    DecodeZ85(DecodeError),
+    Io(Error),
+}

+ Variants

+
Decode(DecodeError)
DecodeZ85(DecodeError)
Io(Error)

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Performs the conversion.

+

Performs the conversion.

+

Performs the conversion.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/encoding/enum.EncodeError.html b/uucore/encoding/enum.EncodeError.html new file mode 100644 index 000000000..fe9584451 --- /dev/null +++ b/uucore/encoding/enum.EncodeError.html @@ -0,0 +1,16 @@ +EncodeError in uucore::encoding - Rust + +

Enum uucore::encoding::EncodeError[][src]

pub enum EncodeError {
+    Z85InputLenNotMultipleOf4,
+}

+ Variants

+
Z85InputLenNotMultipleOf4

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/encoding/enum.Format.html b/uucore/encoding/enum.Format.html new file mode 100644 index 000000000..c2fb66c34 --- /dev/null +++ b/uucore/encoding/enum.Format.html @@ -0,0 +1,29 @@ +Format in uucore::encoding - Rust + +

Enum uucore::encoding::Format[][src]

pub enum Format {
+    Base64,
+    Base64Url,
+    Base32,
+    Base32Hex,
+    Base16,
+    Base2Lsbf,
+    Base2Msbf,
+    Z85,
+}

+ Variants

+
Base64
Base64Url
Base32
Base32Hex
Base16
Base2Lsbf
Base2Msbf
Z85

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/encoding/fn.decode.html b/uucore/encoding/fn.decode.html new file mode 100644 index 000000000..86e6783fd --- /dev/null +++ b/uucore/encoding/fn.decode.html @@ -0,0 +1,3 @@ +decode in uucore::encoding - Rust + +

Function uucore::encoding::decode[][src]

pub fn decode(f: Format, input: &[u8]) -> DecodeResult
\ No newline at end of file diff --git a/uucore/encoding/fn.encode.html b/uucore/encoding/fn.encode.html new file mode 100644 index 000000000..8e13bb38c --- /dev/null +++ b/uucore/encoding/fn.encode.html @@ -0,0 +1,3 @@ +encode in uucore::encoding - Rust + +

Function uucore::encoding::encode[][src]

pub fn encode(f: Format, input: &[u8]) -> Result<String, EncodeError>
\ No newline at end of file diff --git a/uucore/encoding/fn.wrap_print.html b/uucore/encoding/fn.wrap_print.html new file mode 100644 index 000000000..c67f5753a --- /dev/null +++ b/uucore/encoding/fn.wrap_print.html @@ -0,0 +1,3 @@ +wrap_print in uucore::encoding - Rust + +

Function uucore::encoding::wrap_print[][src]

pub fn wrap_print<R: Read>(data: &Data<R>, res: String)
\ No newline at end of file diff --git a/uucore/encoding/fn.wrap_write.html b/uucore/encoding/fn.wrap_write.html new file mode 100644 index 000000000..955355912 --- /dev/null +++ b/uucore/encoding/fn.wrap_write.html @@ -0,0 +1,3 @@ +wrap_write in uucore::encoding - Rust + +

Function uucore::encoding::wrap_write[][src]

pub fn wrap_write<W: Write>(
    writer: W,
    line_wrap: usize,
    res: String
) -> Result<()>
\ No newline at end of file diff --git a/uucore/encoding/index.html b/uucore/encoding/index.html new file mode 100644 index 000000000..57fa7fad3 --- /dev/null +++ b/uucore/encoding/index.html @@ -0,0 +1,7 @@ +uucore::encoding - Rust + +

Module uucore::encoding[][src]

Structs

+
Data

Enums

+
DecodeError
EncodeError
Format

Functions

+
decode
encode
wrap_print
wrap_write

Type Definitions

+
DecodeResult
\ No newline at end of file diff --git a/uucore/encoding/sidebar-items.js b/uucore/encoding/sidebar-items.js new file mode 100644 index 000000000..85174e671 --- /dev/null +++ b/uucore/encoding/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["DecodeError",""],["EncodeError",""],["Format",""]],"fn":[["decode",""],["encode",""],["wrap_print",""],["wrap_write",""]],"struct":[["Data",""]],"type":[["DecodeResult",""]]}); \ No newline at end of file diff --git a/uucore/encoding/struct.Data.html b/uucore/encoding/struct.Data.html new file mode 100644 index 000000000..4c192e5e1 --- /dev/null +++ b/uucore/encoding/struct.Data.html @@ -0,0 +1,12 @@ +Data in uucore::encoding - Rust + +

Struct uucore::encoding::Data[][src]

pub struct Data<R: Read> { /* fields omitted */ }

Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/encoding/type.DecodeResult.html b/uucore/encoding/type.DecodeResult.html new file mode 100644 index 000000000..cc2cddd57 --- /dev/null +++ b/uucore/encoding/type.DecodeResult.html @@ -0,0 +1,3 @@ +DecodeResult in uucore::encoding - Rust + +

Type Definition uucore::encoding::DecodeResult[][src]

type DecodeResult = Result<Vec<u8>, DecodeError>;
\ No newline at end of file diff --git a/uucore/entries/fn.get_groups.html b/uucore/entries/fn.get_groups.html new file mode 100644 index 000000000..21ed06d50 --- /dev/null +++ b/uucore/entries/fn.get_groups.html @@ -0,0 +1,12 @@ +get_groups in uucore::entries - Rust + +

Function uucore::entries::get_groups[][src]

pub fn get_groups() -> IOResult<Vec<gid_t>>
Expand description

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
+

getgroups() returns the supplementary group IDs of the calling +process in list. +If size is zero, list is not modified, but the total number of +supplementary group IDs for the process is returned. This allows +the caller to determine the size of a dynamically allocated list +to be used in a further call to getgroups().

+
+
\ No newline at end of file diff --git a/uucore/entries/fn.get_groups_gnu.html b/uucore/entries/fn.get_groups_gnu.html new file mode 100644 index 000000000..beba27b2f --- /dev/null +++ b/uucore/entries/fn.get_groups_gnu.html @@ -0,0 +1,25 @@ +get_groups_gnu in uucore::entries - Rust + +

Function uucore::entries::get_groups_gnu[][src]

pub fn get_groups_gnu(arg_id: Option<u32>) -> IOResult<Vec<gid_t>>
Expand description

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+

If arg_id is None (default), get_groups_gnu moves the effective +group id (egid) to the first entry in the returned Vector. +If arg_id is Some(x), get_groups_gnu moves the id with value x +to the first entry in the returned Vector. This might be necessary +for id --groups --real if gid and egid are not equal.

+

From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html

+
+

As implied by the definition of supplementary groups, the +effective group ID may appear in the array returned by +getgroups() or it may be returned only by getegid(). Duplication +may exist, but the application needs to call getegid() to be sure +of getting all of the information. Various implementation +variations and administrative sequences cause the set of groups +appearing in the result of getgroups() to vary in order and as to +whether the effective group ID is included, even when the set of +groups is the same (in the mathematical sense of ``set’’). (The +history of a process and its parents could affect the details of +the result.)

+
+
\ No newline at end of file diff --git a/uucore/entries/fn.gid2grp.html b/uucore/entries/fn.gid2grp.html new file mode 100644 index 000000000..1b8df657c --- /dev/null +++ b/uucore/entries/fn.gid2grp.html @@ -0,0 +1,3 @@ +gid2grp in uucore::entries - Rust + +

Function uucore::entries::gid2grp[][src]

pub fn gid2grp(id: gid_t) -> IOResult<String>
\ No newline at end of file diff --git a/uucore/entries/fn.grp2gid.html b/uucore/entries/fn.grp2gid.html new file mode 100644 index 000000000..2b3c89326 --- /dev/null +++ b/uucore/entries/fn.grp2gid.html @@ -0,0 +1,3 @@ +grp2gid in uucore::entries - Rust + +

Function uucore::entries::grp2gid[][src]

pub fn grp2gid(name: &str) -> IOResult<gid_t>
\ No newline at end of file diff --git a/uucore/entries/fn.uid2usr.html b/uucore/entries/fn.uid2usr.html new file mode 100644 index 000000000..b4e464c13 --- /dev/null +++ b/uucore/entries/fn.uid2usr.html @@ -0,0 +1,3 @@ +uid2usr in uucore::entries - Rust + +

Function uucore::entries::uid2usr[][src]

pub fn uid2usr(id: uid_t) -> IOResult<String>
\ No newline at end of file diff --git a/uucore/entries/fn.usr2uid.html b/uucore/entries/fn.usr2uid.html new file mode 100644 index 000000000..5f6ca11d7 --- /dev/null +++ b/uucore/entries/fn.usr2uid.html @@ -0,0 +1,3 @@ +usr2uid in uucore::entries - Rust + +

Function uucore::entries::usr2uid[][src]

pub fn usr2uid(name: &str) -> IOResult<uid_t>
\ No newline at end of file diff --git a/uucore/entries/index.html b/uucore/entries/index.html new file mode 100644 index 000000000..d0af33b09 --- /dev/null +++ b/uucore/entries/index.html @@ -0,0 +1,34 @@ +uucore::entries - Rust + +

Module uucore::entries[][src]

Expand description

Get password/group file entry

+

Examples:

+
+use uucore::entries::{self, Locate};
+
+let root_group = if cfg!(any(target_os = "linux", target_os = "android")) {
+    "root"
+} else {
+    "wheel"
+};
+
+assert_eq!("root", entries::uid2usr(0).unwrap());
+assert_eq!(0, entries::usr2uid("root").unwrap());
+assert!(entries::gid2grp(0).is_ok());
+assert!(entries::grp2gid(root_group).is_ok());
+
+assert!(entries::Passwd::locate(0).is_ok());
+assert!(entries::Passwd::locate("0").is_ok());
+assert!(entries::Passwd::locate("root").is_ok());
+
+assert!(entries::Group::locate(0).is_ok());
+assert!(entries::Group::locate("0").is_ok());
+assert!(entries::Group::locate(root_group).is_ok());
+

Structs

+
Group
Passwd

Traits

+
Locate

Fetch desired entry.

+

Functions

+
get_groups

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
get_groups_gnu

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+
gid2grp
grp2gid
uid2usr
usr2uid
\ No newline at end of file diff --git a/uucore/entries/sidebar-items.js b/uucore/entries/sidebar-items.js new file mode 100644 index 000000000..55270684c --- /dev/null +++ b/uucore/entries/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_groups","From: https://man7.org/linux/man-pages/man2/getgroups.2.html"],["get_groups_gnu","The list of group IDs returned from GNU’s `groups` and GNU’s `id --groups` starts with the effective group ID (egid). This is a wrapper for `get_groups()` to mimic this behavior."],["gid2grp",""],["grp2gid",""],["uid2usr",""],["usr2uid",""]],"struct":[["Group",""],["Passwd",""]],"trait":[["Locate","Fetch desired entry."]]}); \ No newline at end of file diff --git a/uucore/entries/struct.Group.html b/uucore/entries/struct.Group.html new file mode 100644 index 000000000..59814dd35 --- /dev/null +++ b/uucore/entries/struct.Group.html @@ -0,0 +1,14 @@ +Group in uucore::entries - Rust + +

Struct uucore::entries::Group[][src]

pub struct Group { /* fields omitted */ }

Implementations

AKA group.gr_name

+

AKA group.gr_gid

+

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/entries/struct.Passwd.html b/uucore/entries/struct.Passwd.html new file mode 100644 index 000000000..8e6d93e14 --- /dev/null +++ b/uucore/entries/struct.Passwd.html @@ -0,0 +1,39 @@ +Passwd in uucore::entries - Rust + +

Struct uucore::entries::Passwd[][src]

pub struct Passwd { /* fields omitted */ }

Implementations

AKA passwd.pw_name

+

AKA passwd.pw_uid

+

AKA passwd.pw_gid

+

AKA passwd.pw_gecos

+

AKA passwd.pw_shell

+

AKA passwd.pw_dir

+

AKA passwd.pw_passwd

+

This is a wrapper function for libc::getgrouplist.

+

From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html

+
+

If the number of groups of which user is a member is less than or +equal to *ngroups, then the value *ngroups is returned. +If the user is a member of more than *ngroups groups, then +getgrouplist() returns -1. In this case, the value returned in +*ngroups can be used to resize the buffer passed to a further +call getgrouplist().

+
+

However, on macOS/darwin (and maybe others?) getgrouplist does +not update ngroups if ngroups is too small. Therefore, if not +updated by getgrouplist, ngroups needs to be increased in a +loop until getgrouplist stops returning -1.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/entries/trait.Locate.html b/uucore/entries/trait.Locate.html new file mode 100644 index 000000000..f451d65df --- /dev/null +++ b/uucore/entries/trait.Locate.html @@ -0,0 +1,6 @@ +Locate in uucore::entries - Rust + +

Trait uucore::entries::Locate[][src]

pub trait Locate<K> {
+    fn locate(key: K) -> IOResult<Self>
    where
        Self: Sized
; +}
Expand description

Fetch desired entry.

+

Required methods

Implementors

\ No newline at end of file diff --git a/uucore/enum.ConversionResult.html b/uucore/enum.ConversionResult.html new file mode 100644 index 000000000..1d854717b --- /dev/null +++ b/uucore/enum.ConversionResult.html @@ -0,0 +1,18 @@ +ConversionResult in uucore - Rust + +

Enum uucore::ConversionResult[][src]

#[must_use]
+pub enum ConversionResult {
+    Complete(Vec<String>),
+    Lossy(Vec<String>),
+}

+ Variants

+
Complete(Vec<String>)
Lossy(Vec<String>)

Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/enum.InvalidEncodingHandling.html b/uucore/enum.InvalidEncodingHandling.html new file mode 100644 index 000000000..815c76355 --- /dev/null +++ b/uucore/enum.InvalidEncodingHandling.html @@ -0,0 +1,18 @@ +InvalidEncodingHandling in uucore - Rust + +

Enum uucore::InvalidEncodingHandling[][src]

pub enum InvalidEncodingHandling {
+    Ignore,
+    ConvertLossy,
+    Panic,
+}

+ Variants

+
Ignore
ConvertLossy
Panic

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/error/fn.get_exit_code.html b/uucore/error/fn.get_exit_code.html new file mode 100644 index 000000000..30af3b510 --- /dev/null +++ b/uucore/error/fn.get_exit_code.html @@ -0,0 +1,5 @@ +get_exit_code in uucore::error - Rust + +

Function uucore::error::get_exit_code[][src]

pub fn get_exit_code() -> i32
Expand description

Get the last exit code set with set_exit_code. +The default value is 0.

+
\ No newline at end of file diff --git a/uucore/error/fn.set_exit_code.html b/uucore/error/fn.set_exit_code.html new file mode 100644 index 000000000..7cdd7536c --- /dev/null +++ b/uucore/error/fn.set_exit_code.html @@ -0,0 +1,21 @@ +set_exit_code in uucore::error - Rust + +

Function uucore::error::set_exit_code[][src]

pub fn set_exit_code(code: i32)
Expand description

Set the exit code for the program if uumain returns Ok(()).

+

This function is most useful for non-fatal errors, for example when applying an operation to +multiple files:

+ +
+use uucore::error::{UResult, set_exit_code};
+
+fn uumain(args: impl uucore::Args) -> UResult<()> {
+    ...
+    for file in files {
+        let res = some_operation_that_might_fail(file);
+        match res {
+            Ok() => {},
+            Err(_) => set_exit_code(1),
+        }
+    }
+    Ok(()) // If any of the operations failed, 1 is returned.
+}
+
\ No newline at end of file diff --git a/uucore/error/index.html b/uucore/error/index.html new file mode 100644 index 000000000..7769ecd51 --- /dev/null +++ b/uucore/error/index.html @@ -0,0 +1,70 @@ +uucore::error - Rust + +

Module uucore::error[][src]

Expand description

All utils return exit with an exit code. Usually, the following scheme is used:

+
    +
  • 0: succeeded
  • +
  • 1: minor problems
  • +
  • 2: major problems
  • +
+

This module provides types to reconcile these exit codes with idiomatic Rust error +handling. This has a couple advantages over manually using std::process::exit:

+
    +
  1. It enables the use of ?, map_err, unwrap_or, etc. in uumain.
  2. +
  3. It encourages the use of UResult/Result in functions in the utils.
  4. +
  5. The error messages are largely standardized across utils.
  6. +
  7. Standardized error messages can be created from external result types +(i.e. std::io::Result & clap::ClapResult).
  8. +
  9. set_exit_code takes away the burden of manually tracking exit codes for non-fatal errors.
  10. +
+

Usage

+

The signature of a typical util should be:

+ +
+fn uumain(args: impl uucore::Args) -> UResult<()> {
+    ...
+}
+

UResult is a simple wrapper around Result with a custom error trait: UError. The +most important difference with types implementing std::error::Error is that UErrors +can specify the exit code of the program when they are returned from uumain:

+
    +
  • When Ok is returned, the code set with set_exit_code is used as exit code. If +set_exit_code was not used, then 0 is used.
  • +
  • When Err is returned, the code corresponding with the error is used as exit code and the +error message is displayed.
  • +
+

Additionally, the errors can be displayed manually with the show and show_if_err macros:

+ +
+let res = Err(USimpleError::new(1, "Error!!"));
+show_if_err!(res);
+// or
+if let Err(e) = res {
+   show!(e);
+}
+

Note: The show and show_if_err macros set the exit code of the program using +set_exit_code. See the documentation on that function for more information.

+

Guidelines

+
    +
  • Use error types from uucore where possible.
  • +
  • Add error types to uucore if an error appears in multiple utils.
  • +
  • Prefer proper custom error types over ExitCode and USimpleError.
  • +
  • USimpleError may be used in small utils with simple error handling.
  • +
  • Using ExitCode is not recommended but can be useful for converting utils to use +UResult.
  • +
+

Structs

+
ExitCode

A special error type that does not print any message when returned from +uumain. Especially useful for porting utilities to using UResult.

+
UIoError

Wrapper type around std::io::Error.

+
USimpleError

A simple error type with an exit code and a message that implements UError.

+
UUsageError

Traits

+
FromIo

Enables the conversion from std::io::Error to UError and from std::io::Result to +UResult.

+
UError

Custom errors defined by the utils and uucore.

+

Functions

+
get_exit_code

Get the last exit code set with set_exit_code. +The default value is 0.

+
set_exit_code

Set the exit code for the program if uumain returns Ok(()).

+

Type Definitions

+
UResult

Result type that should be returned by all utils.

+
\ No newline at end of file diff --git a/uucore/error/sidebar-items.js b/uucore/error/sidebar-items.js new file mode 100644 index 000000000..2abacd2ab --- /dev/null +++ b/uucore/error/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_exit_code","Get the last exit code set with [`set_exit_code`]. The default value is `0`."],["set_exit_code","Set the exit code for the program if `uumain` returns `Ok(())`."]],"struct":[["ExitCode","A special error type that does not print any message when returned from `uumain`. Especially useful for porting utilities to using [`UResult`]."],["UIoError","Wrapper type around [`std::io::Error`]."],["USimpleError","A simple error type with an exit code and a message that implements [`UError`]."],["UUsageError",""]],"trait":[["FromIo","Enables the conversion from [`std::io::Error`] to [`UError`] and from [`std::io::Result`] to [`UResult`]."],["UError","Custom errors defined by the utils and `uucore`."]],"type":[["UResult","Result type that should be returned by all utils."]]}); \ No newline at end of file diff --git a/uucore/error/struct.ExitCode.html b/uucore/error/struct.ExitCode.html new file mode 100644 index 000000000..fa5df37db --- /dev/null +++ b/uucore/error/struct.ExitCode.html @@ -0,0 +1,34 @@ +ExitCode in uucore::error - Rust + +

Struct uucore::error::ExitCode[][src]

pub struct ExitCode(pub i32);
Expand description

A special error type that does not print any message when returned from +uumain. Especially useful for porting utilities to using UResult.

+

There are two ways to construct an ExitCode:

+ +
+use uucore::error::{ExitCode, UResult};
+// Explicit
+let res: UResult<()> = Err(ExitCode(1).into());
+
+// Using into on `i32`:
+let res: UResult<()> = Err(1.into());
+

This type is especially useful for a trivial conversion from utils returning i32 to +returning UResult.

+

Implementations

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Error code of a custom error. Read more

+

Print usage help to a custom error. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/error/struct.UIoError.html b/uucore/error/struct.UIoError.html new file mode 100644 index 000000000..6b491f45f --- /dev/null +++ b/uucore/error/struct.UIoError.html @@ -0,0 +1,42 @@ +UIoError in uucore::error - Rust + +

Struct uucore::error::UIoError[][src]

pub struct UIoError { /* fields omitted */ }
Expand description

Wrapper type around std::io::Error.

+

The messages displayed by UIoError should match the error messages displayed by GNU +coreutils.

+

There are two ways to construct this type: with UIoError::new or by calling the +FromIo::map_err_context method on a std::io::Result or std::io::Error.

+ +
+use uucore::error::{FromIo, UResult, UIoError, UError};
+use std::fs::File;
+use std::path::Path;
+let path = Path::new("test.txt");
+
+// Manual construction
+let e: Box<dyn UError> = UIoError::new(
+    std::io::ErrorKind::NotFound,
+    format!("cannot access '{}'", path.display())
+);
+let res: UResult<()> = Err(e.into());
+
+// Converting from an `std::io::Error`.
+let res: UResult<File> = File::open(path).map_err_context(|| format!("cannot access '{}'", path.display()));
+

Implementations

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Error code of a custom error. Read more

+

Print usage help to a custom error. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/error/struct.USimpleError.html b/uucore/error/struct.USimpleError.html new file mode 100644 index 000000000..bd4283d21 --- /dev/null +++ b/uucore/error/struct.USimpleError.html @@ -0,0 +1,33 @@ +USimpleError in uucore::error - Rust + +

Struct uucore::error::USimpleError[][src]

pub struct USimpleError {
+    pub code: i32,
+    pub message: String,
+}
Expand description

A simple error type with an exit code and a message that implements UError.

+ +
+use uucore::error::{UResult, USimpleError};
+let err = USimpleError { code: 1, message: "error!".into()};
+let res: UResult<()> = Err(err.into());
+// or using the `new` method:
+let res: UResult<()> = Err(USimpleError::new(1, "error!"));
+

+ Fields

code: i32message: String

Implementations

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Error code of a custom error. Read more

+

Print usage help to a custom error. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/error/struct.UUsageError.html b/uucore/error/struct.UUsageError.html new file mode 100644 index 000000000..d4e54581b --- /dev/null +++ b/uucore/error/struct.UUsageError.html @@ -0,0 +1,25 @@ +UUsageError in uucore::error - Rust + +

Struct uucore::error::UUsageError[][src]

pub struct UUsageError {
+    pub code: i32,
+    pub message: String,
+}

+ Fields

code: i32message: String

Implementations

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

Error code of a custom error. Read more

+

Print usage help to a custom error. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/error/trait.FromIo.html b/uucore/error/trait.FromIo.html new file mode 100644 index 000000000..822254b7c --- /dev/null +++ b/uucore/error/trait.FromIo.html @@ -0,0 +1,7 @@ +FromIo in uucore::error - Rust + +

Trait uucore::error::FromIo[][src]

pub trait FromIo<T> {
+    fn map_err_context(self, context: impl FnOnce() -> String) -> T;
+}
Expand description

Enables the conversion from std::io::Error to UError and from std::io::Result to +UResult.

+

Required methods

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/uucore/error/trait.UError.html b/uucore/error/trait.UError.html new file mode 100644 index 000000000..27a2be4a2 --- /dev/null +++ b/uucore/error/trait.UError.html @@ -0,0 +1,142 @@ +UError in uucore::error - Rust + +

Trait uucore::error::UError[][src]

pub trait UError: Error + Send {
+    fn code(&self) -> i32 { ... }
+
fn usage(&self) -> bool { ... } +}
Expand description

Custom errors defined by the utils and uucore.

+

All errors should implement std::error::Error, std::fmt::Display and +std::fmt::Debug and have an additional code method that specifies the +exit code of the program if the error is returned from uumain.

+

An example of a custom error from ls:

+ +
+use uucore::error::{UError, UResult};
+use std::{
+    error::Error,
+    fmt::{Display, Debug},
+    path::PathBuf
+};
+
+#[derive(Debug)]
+enum LsError {
+    InvalidLineWidth(String),
+    NoMetadata(PathBuf),
+}
+
+impl UError for LsError {
+    fn code(&self) -> i32 {
+        match self {
+            LsError::InvalidLineWidth(_) => 2,
+            LsError::NoMetadata(_) => 1,
+        }
+    }
+}
+
+impl Error for LsError {}
+
+impl Display for LsError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            LsError::InvalidLineWidth(s) => write!(f, "invalid line width: '{}'", s),
+            LsError::NoMetadata(p) => write!(f, "could not open file: '{}'", p.display()),
+        }
+    }
+}
+

The main routine would look like this:

+ +
+#[uucore_procs::gen_uumain]
+pub fn uumain(args: impl uucore::Args) -> UResult<()> {
+    // Perform computations here ...
+    return Err(LsError::InvalidLineWidth(String::from("test")).into())
+}
+

The call to into() is required to convert the LsError to +Box<dyn UError>. The implementation for From is provided automatically.

+

A crate like quick_error might +also be used, but will still require an impl for the code method.

+

Provided methods

Error code of a custom error.

+

Set a return value for each variant of an enum-type to associate an +error code (which is returned to the system shell) with an error +variant.

+

Example

+
+use uucore::error::{UError};
+use std::{
+    error::Error,
+    fmt::{Display, Debug},
+    path::PathBuf
+};
+
+#[derive(Debug)]
+enum MyError {
+    Foo(String),
+    Bar(PathBuf),
+    Bing(),
+}
+
+impl UError for MyError {
+    fn code(&self) -> i32 {
+        match self {
+            MyError::Foo(_) => 2,
+            // All other errors yield the same error code, there's no
+            // need to list them explicitly.
+            _ => 1,
+        }
+    }
+}
+
+impl Error for MyError {}
+
+impl Display for MyError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use MyError as ME;
+        match self {
+            ME::Foo(s) => write!(f, "Unknown Foo: '{}'", s),
+            ME::Bar(p) => write!(f, "Couldn't find Bar: '{}'", p.display()),
+            ME::Bing() => write!(f, "Exterminate!"),
+        }
+    }
+}
+

Print usage help to a custom error.

+

Return true or false to control whether a short usage help is printed +below the error message. The usage help is in the format: “Try {name} --help for more information.” and printed only if true is returned.

+

Example

+
+use uucore::error::{UError};
+use std::{
+    error::Error,
+    fmt::{Display, Debug},
+    path::PathBuf
+};
+
+#[derive(Debug)]
+enum MyError {
+    Foo(String),
+    Bar(PathBuf),
+    Bing(),
+}
+
+impl UError for MyError {
+    fn usage(&self) -> bool {
+        match self {
+            // This will have a short usage help appended
+            MyError::Bar(_) => true,
+            // These matches won't have a short usage help appended
+            _ => false,
+        }
+    }
+}
+
+impl Error for MyError {}
+
+impl Display for MyError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        use MyError as ME;
+        match self {
+            ME::Foo(s) => write!(f, "Unknown Foo: '{}'", s),
+            ME::Bar(p) => write!(f, "Couldn't find Bar: '{}'", p.display()),
+            ME::Bing() => write!(f, "Exterminate!"),
+        }
+    }
+}
+

Implementors

\ No newline at end of file diff --git a/uucore/error/type.UResult.html b/uucore/error/type.UResult.html new file mode 100644 index 000000000..90fe5e925 --- /dev/null +++ b/uucore/error/type.UResult.html @@ -0,0 +1,4 @@ +UResult in uucore::error - Rust + +

Type Definition uucore::error::UResult[][src]

type UResult<T> = Result<T, Box<dyn UError>>;
Expand description

Result type that should be returned by all utils.

+
\ No newline at end of file diff --git a/uucore/features/encoding/enum.DecodeError.html b/uucore/features/encoding/enum.DecodeError.html new file mode 100644 index 000000000..9fe94b80d --- /dev/null +++ b/uucore/features/encoding/enum.DecodeError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/enum.DecodeError.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/enum.EncodeError.html b/uucore/features/encoding/enum.EncodeError.html new file mode 100644 index 000000000..9ebeeda59 --- /dev/null +++ b/uucore/features/encoding/enum.EncodeError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/enum.EncodeError.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/enum.Format.html b/uucore/features/encoding/enum.Format.html new file mode 100644 index 000000000..e1906cd3a --- /dev/null +++ b/uucore/features/encoding/enum.Format.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/enum.Format.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/fn.decode.html b/uucore/features/encoding/fn.decode.html new file mode 100644 index 000000000..e9de41e2e --- /dev/null +++ b/uucore/features/encoding/fn.decode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/fn.decode.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/fn.encode.html b/uucore/features/encoding/fn.encode.html new file mode 100644 index 000000000..ef94d7111 --- /dev/null +++ b/uucore/features/encoding/fn.encode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/fn.encode.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/fn.wrap_print.html b/uucore/features/encoding/fn.wrap_print.html new file mode 100644 index 000000000..6475da2b2 --- /dev/null +++ b/uucore/features/encoding/fn.wrap_print.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/fn.wrap_print.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/fn.wrap_write.html b/uucore/features/encoding/fn.wrap_write.html new file mode 100644 index 000000000..a99951209 --- /dev/null +++ b/uucore/features/encoding/fn.wrap_write.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/fn.wrap_write.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/index.html b/uucore/features/encoding/index.html new file mode 100644 index 000000000..2ff50eb20 --- /dev/null +++ b/uucore/features/encoding/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/struct.Data.html b/uucore/features/encoding/struct.Data.html new file mode 100644 index 000000000..76b55cebf --- /dev/null +++ b/uucore/features/encoding/struct.Data.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/struct.Data.html...

+ + + \ No newline at end of file diff --git a/uucore/features/encoding/type.DecodeResult.html b/uucore/features/encoding/type.DecodeResult.html new file mode 100644 index 000000000..de08fb3e1 --- /dev/null +++ b/uucore/features/encoding/type.DecodeResult.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/encoding/type.DecodeResult.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/fn.get_groups.html b/uucore/features/entries/fn.get_groups.html new file mode 100644 index 000000000..80ba0167f --- /dev/null +++ b/uucore/features/entries/fn.get_groups.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/fn.get_groups.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/fn.get_groups_gnu.html b/uucore/features/entries/fn.get_groups_gnu.html new file mode 100644 index 000000000..4f38a2c38 --- /dev/null +++ b/uucore/features/entries/fn.get_groups_gnu.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/fn.get_groups_gnu.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/fn.gid2grp.html b/uucore/features/entries/fn.gid2grp.html new file mode 100644 index 000000000..3e833ee38 --- /dev/null +++ b/uucore/features/entries/fn.gid2grp.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/fn.gid2grp.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/fn.grp2gid.html b/uucore/features/entries/fn.grp2gid.html new file mode 100644 index 000000000..faf1211d4 --- /dev/null +++ b/uucore/features/entries/fn.grp2gid.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/fn.grp2gid.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/fn.uid2usr.html b/uucore/features/entries/fn.uid2usr.html new file mode 100644 index 000000000..739dee1a7 --- /dev/null +++ b/uucore/features/entries/fn.uid2usr.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/fn.uid2usr.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/fn.usr2uid.html b/uucore/features/entries/fn.usr2uid.html new file mode 100644 index 000000000..c814861b7 --- /dev/null +++ b/uucore/features/entries/fn.usr2uid.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/fn.usr2uid.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/index.html b/uucore/features/entries/index.html new file mode 100644 index 000000000..ca874c09f --- /dev/null +++ b/uucore/features/entries/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/struct.Group.html b/uucore/features/entries/struct.Group.html new file mode 100644 index 000000000..25ff7d2c3 --- /dev/null +++ b/uucore/features/entries/struct.Group.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/struct.Group.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/struct.Passwd.html b/uucore/features/entries/struct.Passwd.html new file mode 100644 index 000000000..1cb03c188 --- /dev/null +++ b/uucore/features/entries/struct.Passwd.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/struct.Passwd.html...

+ + + \ No newline at end of file diff --git a/uucore/features/entries/trait.Locate.html b/uucore/features/entries/trait.Locate.html new file mode 100644 index 000000000..0fca81cd2 --- /dev/null +++ b/uucore/features/entries/trait.Locate.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/entries/trait.Locate.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/enum.MissingHandling.html b/uucore/features/fs/enum.MissingHandling.html new file mode 100644 index 000000000..bc30750bb --- /dev/null +++ b/uucore/features/fs/enum.MissingHandling.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/enum.MissingHandling.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/enum.ResolveMode.html b/uucore/features/fs/enum.ResolveMode.html new file mode 100644 index 000000000..8744dfd6c --- /dev/null +++ b/uucore/features/fs/enum.ResolveMode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/enum.ResolveMode.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/fn.canonicalize.html b/uucore/features/fs/fn.canonicalize.html new file mode 100644 index 000000000..a980bdee8 --- /dev/null +++ b/uucore/features/fs/fn.canonicalize.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/fn.canonicalize.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/fn.display_permissions.html b/uucore/features/fs/fn.display_permissions.html new file mode 100644 index 000000000..6ffac7ab8 --- /dev/null +++ b/uucore/features/fs/fn.display_permissions.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/fn.display_permissions.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/fn.display_permissions_unix.html b/uucore/features/fs/fn.display_permissions_unix.html new file mode 100644 index 000000000..54234db6a --- /dev/null +++ b/uucore/features/fs/fn.display_permissions_unix.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/fn.display_permissions_unix.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/fn.normalize_path.html b/uucore/features/fs/fn.normalize_path.html new file mode 100644 index 000000000..32755fa26 --- /dev/null +++ b/uucore/features/fs/fn.normalize_path.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/fn.normalize_path.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/fn.resolve_relative_path.html b/uucore/features/fs/fn.resolve_relative_path.html new file mode 100644 index 000000000..25f44513f --- /dev/null +++ b/uucore/features/fs/fn.resolve_relative_path.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/fn.resolve_relative_path.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fs/index.html b/uucore/features/fs/index.html new file mode 100644 index 000000000..d5b57ff3c --- /dev/null +++ b/uucore/features/fs/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fs/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.StatFs.html b/uucore/features/fsext/fn.StatFs.html new file mode 100644 index 000000000..c2c70fe0a --- /dev/null +++ b/uucore/features/fsext/fn.StatFs.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.statfs_fn.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.pretty_filetype.html b/uucore/features/fsext/fn.pretty_filetype.html new file mode 100644 index 000000000..ddd6de96f --- /dev/null +++ b/uucore/features/fsext/fn.pretty_filetype.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.pretty_filetype.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.pretty_fstype.html b/uucore/features/fsext/fn.pretty_fstype.html new file mode 100644 index 000000000..a90e33f49 --- /dev/null +++ b/uucore/features/fsext/fn.pretty_fstype.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.pretty_fstype.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.pretty_time.html b/uucore/features/fsext/fn.pretty_time.html new file mode 100644 index 000000000..aa37e8a78 --- /dev/null +++ b/uucore/features/fsext/fn.pretty_time.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.pretty_time.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.read_fs_list.html b/uucore/features/fsext/fn.read_fs_list.html new file mode 100644 index 000000000..06968b1da --- /dev/null +++ b/uucore/features/fsext/fn.read_fs_list.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.read_fs_list.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.statfs.html b/uucore/features/fsext/fn.statfs.html new file mode 100644 index 000000000..ae7f4090d --- /dev/null +++ b/uucore/features/fsext/fn.statfs.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.statfs.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/fn.statfs_fn.html b/uucore/features/fsext/fn.statfs_fn.html new file mode 100644 index 000000000..c2c70fe0a --- /dev/null +++ b/uucore/features/fsext/fn.statfs_fn.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/fn.statfs_fn.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/index.html b/uucore/features/fsext/index.html new file mode 100644 index 000000000..3742bf9e1 --- /dev/null +++ b/uucore/features/fsext/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/struct.FsUsage.html b/uucore/features/fsext/struct.FsUsage.html new file mode 100644 index 000000000..585337da3 --- /dev/null +++ b/uucore/features/fsext/struct.FsUsage.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/struct.FsUsage.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/struct.MountInfo.html b/uucore/features/fsext/struct.MountInfo.html new file mode 100644 index 000000000..858ab9df0 --- /dev/null +++ b/uucore/features/fsext/struct.MountInfo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/struct.MountInfo.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/struct.StatFs.html b/uucore/features/fsext/struct.StatFs.html new file mode 100644 index 000000000..e5274f32e --- /dev/null +++ b/uucore/features/fsext/struct.StatFs.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/struct.statfs_fn.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/struct.statfs_fn.html b/uucore/features/fsext/struct.statfs_fn.html new file mode 100644 index 000000000..e5274f32e --- /dev/null +++ b/uucore/features/fsext/struct.statfs_fn.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/struct.statfs_fn.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/trait.BirthTime.html b/uucore/features/fsext/trait.BirthTime.html new file mode 100644 index 000000000..b98156b00 --- /dev/null +++ b/uucore/features/fsext/trait.BirthTime.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/trait.BirthTime.html...

+ + + \ No newline at end of file diff --git a/uucore/features/fsext/trait.FsMeta.html b/uucore/features/fsext/trait.FsMeta.html new file mode 100644 index 000000000..80fc834fe --- /dev/null +++ b/uucore/features/fsext/trait.FsMeta.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/fsext/trait.FsMeta.html...

+ + + \ No newline at end of file diff --git a/uucore/features/mode/fn.parse_mode.html b/uucore/features/mode/fn.parse_mode.html new file mode 100644 index 000000000..0c5922dcd --- /dev/null +++ b/uucore/features/mode/fn.parse_mode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/mode/fn.parse_mode.html...

+ + + \ No newline at end of file diff --git a/uucore/features/mode/fn.parse_numeric.html b/uucore/features/mode/fn.parse_numeric.html new file mode 100644 index 000000000..0747b9eef --- /dev/null +++ b/uucore/features/mode/fn.parse_numeric.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/mode/fn.parse_numeric.html...

+ + + \ No newline at end of file diff --git a/uucore/features/mode/fn.parse_symbolic.html b/uucore/features/mode/fn.parse_symbolic.html new file mode 100644 index 000000000..29c513eb3 --- /dev/null +++ b/uucore/features/mode/fn.parse_symbolic.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/mode/fn.parse_symbolic.html...

+ + + \ No newline at end of file diff --git a/uucore/features/mode/index.html b/uucore/features/mode/index.html new file mode 100644 index 000000000..68f95dafc --- /dev/null +++ b/uucore/features/mode/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/mode/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/constant.FTS_COMFOLLOW.html b/uucore/features/perms/constant.FTS_COMFOLLOW.html new file mode 100644 index 000000000..f46cbef1e --- /dev/null +++ b/uucore/features/perms/constant.FTS_COMFOLLOW.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/constant.FTS_COMFOLLOW.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/constant.FTS_LOGICAL.html b/uucore/features/perms/constant.FTS_LOGICAL.html new file mode 100644 index 000000000..5366bd3d8 --- /dev/null +++ b/uucore/features/perms/constant.FTS_LOGICAL.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/constant.FTS_LOGICAL.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/constant.FTS_PHYSICAL.html b/uucore/features/perms/constant.FTS_PHYSICAL.html new file mode 100644 index 000000000..1d77a4288 --- /dev/null +++ b/uucore/features/perms/constant.FTS_PHYSICAL.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/constant.FTS_PHYSICAL.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/enum.IfFrom.html b/uucore/features/perms/enum.IfFrom.html new file mode 100644 index 000000000..8955c772c --- /dev/null +++ b/uucore/features/perms/enum.IfFrom.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/enum.IfFrom.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/enum.VerbosityLevel.html b/uucore/features/perms/enum.VerbosityLevel.html new file mode 100644 index 000000000..64d4d3377 --- /dev/null +++ b/uucore/features/perms/enum.VerbosityLevel.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/enum.VerbosityLevel.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/fn.wrap_chown.html b/uucore/features/perms/fn.wrap_chown.html new file mode 100644 index 000000000..457892f41 --- /dev/null +++ b/uucore/features/perms/fn.wrap_chown.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/fn.wrap_chown.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/index.html b/uucore/features/perms/index.html new file mode 100644 index 000000000..822a521ba --- /dev/null +++ b/uucore/features/perms/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/struct.ChownExecutor.html b/uucore/features/perms/struct.ChownExecutor.html new file mode 100644 index 000000000..b167d2416 --- /dev/null +++ b/uucore/features/perms/struct.ChownExecutor.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/struct.ChownExecutor.html...

+ + + \ No newline at end of file diff --git a/uucore/features/perms/struct.Verbosity.html b/uucore/features/perms/struct.Verbosity.html new file mode 100644 index 000000000..cbb819b5e --- /dev/null +++ b/uucore/features/perms/struct.Verbosity.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/perms/struct.Verbosity.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/enum.ExitStatus.html b/uucore/features/process/enum.ExitStatus.html new file mode 100644 index 000000000..340f80a27 --- /dev/null +++ b/uucore/features/process/enum.ExitStatus.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/enum.ExitStatus.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/fn.getegid.html b/uucore/features/process/fn.getegid.html new file mode 100644 index 000000000..b48580252 --- /dev/null +++ b/uucore/features/process/fn.getegid.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/fn.getegid.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/fn.geteuid.html b/uucore/features/process/fn.geteuid.html new file mode 100644 index 000000000..963a3d09c --- /dev/null +++ b/uucore/features/process/fn.geteuid.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/fn.geteuid.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/fn.getgid.html b/uucore/features/process/fn.getgid.html new file mode 100644 index 000000000..c4c6c73c0 --- /dev/null +++ b/uucore/features/process/fn.getgid.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/fn.getgid.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/fn.getuid.html b/uucore/features/process/fn.getuid.html new file mode 100644 index 000000000..59065103c --- /dev/null +++ b/uucore/features/process/fn.getuid.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/fn.getuid.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/index.html b/uucore/features/process/index.html new file mode 100644 index 000000000..fab407d06 --- /dev/null +++ b/uucore/features/process/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/process/trait.ChildExt.html b/uucore/features/process/trait.ChildExt.html new file mode 100644 index 000000000..db70b8378 --- /dev/null +++ b/uucore/features/process/trait.ChildExt.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/process/trait.ChildExt.html...

+ + + \ No newline at end of file diff --git a/uucore/features/ringbuffer/index.html b/uucore/features/ringbuffer/index.html new file mode 100644 index 000000000..5cc8f7d52 --- /dev/null +++ b/uucore/features/ringbuffer/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/ringbuffer/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/ringbuffer/struct.RingBuffer.html b/uucore/features/ringbuffer/struct.RingBuffer.html new file mode 100644 index 000000000..8e1387ccf --- /dev/null +++ b/uucore/features/ringbuffer/struct.RingBuffer.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/ringbuffer/struct.RingBuffer.html...

+ + + \ No newline at end of file diff --git a/uucore/features/signals/fn.is_signal.html b/uucore/features/signals/fn.is_signal.html new file mode 100644 index 000000000..49109f9fe --- /dev/null +++ b/uucore/features/signals/fn.is_signal.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/signals/fn.is_signal.html...

+ + + \ No newline at end of file diff --git a/uucore/features/signals/fn.signal_by_name_or_value.html b/uucore/features/signals/fn.signal_by_name_or_value.html new file mode 100644 index 000000000..7a60b6c6f --- /dev/null +++ b/uucore/features/signals/fn.signal_by_name_or_value.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/signals/fn.signal_by_name_or_value.html...

+ + + \ No newline at end of file diff --git a/uucore/features/signals/fn.signal_name_by_value.html b/uucore/features/signals/fn.signal_name_by_value.html new file mode 100644 index 000000000..a58453c3a --- /dev/null +++ b/uucore/features/signals/fn.signal_name_by_value.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/signals/fn.signal_name_by_value.html...

+ + + \ No newline at end of file diff --git a/uucore/features/signals/index.html b/uucore/features/signals/index.html new file mode 100644 index 000000000..81cb86805 --- /dev/null +++ b/uucore/features/signals/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/signals/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/signals/static.ALL_SIGNALS.html b/uucore/features/signals/static.ALL_SIGNALS.html new file mode 100644 index 000000000..139a0eebd --- /dev/null +++ b/uucore/features/signals/static.ALL_SIGNALS.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/signals/static.ALL_SIGNALS.html...

+ + + \ No newline at end of file diff --git a/uucore/features/signals/static.DEFAULT_SIGNAL.html b/uucore/features/signals/static.DEFAULT_SIGNAL.html new file mode 100644 index 000000000..d4964b3a3 --- /dev/null +++ b/uucore/features/signals/static.DEFAULT_SIGNAL.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/signals/static.DEFAULT_SIGNAL.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/fn.endutxent.html b/uucore/features/utmpx/fn.endutxent.html new file mode 100644 index 000000000..4a0b9cd3f --- /dev/null +++ b/uucore/features/utmpx/fn.endutxent.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/fn.endutxent.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/fn.getutxent.html b/uucore/features/utmpx/fn.getutxent.html new file mode 100644 index 000000000..52334fce0 --- /dev/null +++ b/uucore/features/utmpx/fn.getutxent.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/fn.getutxent.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/fn.setutxent.html b/uucore/features/utmpx/fn.setutxent.html new file mode 100644 index 000000000..15c8d5a61 --- /dev/null +++ b/uucore/features/utmpx/fn.setutxent.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/fn.setutxent.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/fn.utmpxname.html b/uucore/features/utmpx/fn.utmpxname.html new file mode 100644 index 000000000..aab737dd3 --- /dev/null +++ b/uucore/features/utmpx/fn.utmpxname.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/fn.utmpxname.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/index.html b/uucore/features/utmpx/index.html new file mode 100644 index 000000000..44b1449e0 --- /dev/null +++ b/uucore/features/utmpx/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/struct.Utmpx.html b/uucore/features/utmpx/struct.Utmpx.html new file mode 100644 index 000000000..1d46b9bc7 --- /dev/null +++ b/uucore/features/utmpx/struct.Utmpx.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/struct.Utmpx.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/struct.UtmpxIter.html b/uucore/features/utmpx/struct.UtmpxIter.html new file mode 100644 index 000000000..d1e74b3c3 --- /dev/null +++ b/uucore/features/utmpx/struct.UtmpxIter.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/utmpx/struct.UtmpxIter.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.ACCOUNTING.html b/uucore/features/utmpx/ut/constant.ACCOUNTING.html new file mode 100644 index 000000000..b567f0581 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.ACCOUNTING.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.ACCOUNTING.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.BOOT_TIME.html b/uucore/features/utmpx/ut/constant.BOOT_TIME.html new file mode 100644 index 000000000..0448fe874 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.BOOT_TIME.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.BOOT_TIME.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.DEAD_PROCESS.html b/uucore/features/utmpx/ut/constant.DEAD_PROCESS.html new file mode 100644 index 000000000..ad1ccac25 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.DEAD_PROCESS.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.DEAD_PROCESS.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.EMPTY.html b/uucore/features/utmpx/ut/constant.EMPTY.html new file mode 100644 index 000000000..0db75e022 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.EMPTY.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.EMPTY.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.INIT_PROCESS.html b/uucore/features/utmpx/ut/constant.INIT_PROCESS.html new file mode 100644 index 000000000..be258642b --- /dev/null +++ b/uucore/features/utmpx/ut/constant.INIT_PROCESS.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.INIT_PROCESS.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.LOGIN_PROCESS.html b/uucore/features/utmpx/ut/constant.LOGIN_PROCESS.html new file mode 100644 index 000000000..39f27d0b1 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.LOGIN_PROCESS.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.LOGIN_PROCESS.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.NEW_TIME.html b/uucore/features/utmpx/ut/constant.NEW_TIME.html new file mode 100644 index 000000000..436ed9c3e --- /dev/null +++ b/uucore/features/utmpx/ut/constant.NEW_TIME.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.NEW_TIME.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.OLD_TIME.html b/uucore/features/utmpx/ut/constant.OLD_TIME.html new file mode 100644 index 000000000..bc6e4d291 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.OLD_TIME.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.OLD_TIME.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.RUN_LVL.html b/uucore/features/utmpx/ut/constant.RUN_LVL.html new file mode 100644 index 000000000..fc4223ad9 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.RUN_LVL.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.RUN_LVL.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.USER_PROCESS.html b/uucore/features/utmpx/ut/constant.USER_PROCESS.html new file mode 100644 index 000000000..b3eb15466 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.USER_PROCESS.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.USER_PROCESS.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.UT_HOSTSIZE.html b/uucore/features/utmpx/ut/constant.UT_HOSTSIZE.html new file mode 100644 index 000000000..435d3d06a --- /dev/null +++ b/uucore/features/utmpx/ut/constant.UT_HOSTSIZE.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.UT_HOSTSIZE.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.UT_IDSIZE.html b/uucore/features/utmpx/ut/constant.UT_IDSIZE.html new file mode 100644 index 000000000..5c5b0b3dc --- /dev/null +++ b/uucore/features/utmpx/ut/constant.UT_IDSIZE.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.UT_IDSIZE.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.UT_LINESIZE.html b/uucore/features/utmpx/ut/constant.UT_LINESIZE.html new file mode 100644 index 000000000..1c9be4f22 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.UT_LINESIZE.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.UT_LINESIZE.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/constant.UT_NAMESIZE.html b/uucore/features/utmpx/ut/constant.UT_NAMESIZE.html new file mode 100644 index 000000000..b03d79421 --- /dev/null +++ b/uucore/features/utmpx/ut/constant.UT_NAMESIZE.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/constant.UT_NAMESIZE.html...

+ + + \ No newline at end of file diff --git a/uucore/features/utmpx/ut/static.DEFAULT_FILE.html b/uucore/features/utmpx/ut/static.DEFAULT_FILE.html new file mode 100644 index 000000000..ae0ec8896 --- /dev/null +++ b/uucore/features/utmpx/ut/static.DEFAULT_FILE.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../uucore/utmpx/static.DEFAULT_FILE.html...

+ + + \ No newline at end of file diff --git a/uucore/features/zero_copy/index.html b/uucore/features/zero_copy/index.html new file mode 100644 index 000000000..be46e34c9 --- /dev/null +++ b/uucore/features/zero_copy/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/zero_copy/index.html...

+ + + \ No newline at end of file diff --git a/uucore/features/zero_copy/struct.ZeroCopyWriter.html b/uucore/features/zero_copy/struct.ZeroCopyWriter.html new file mode 100644 index 000000000..f6bef23f0 --- /dev/null +++ b/uucore/features/zero_copy/struct.ZeroCopyWriter.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/zero_copy/struct.ZeroCopyWriter.html...

+ + + \ No newline at end of file diff --git a/uucore/features/zero_copy/trait.AsRawObject.html b/uucore/features/zero_copy/trait.AsRawObject.html new file mode 100644 index 000000000..3fd269c03 --- /dev/null +++ b/uucore/features/zero_copy/trait.AsRawObject.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/zero_copy/trait.AsRawObject.html...

+ + + \ No newline at end of file diff --git a/uucore/features/zero_copy/trait.FromRawObject.html b/uucore/features/zero_copy/trait.FromRawObject.html new file mode 100644 index 000000000..355b6c92d --- /dev/null +++ b/uucore/features/zero_copy/trait.FromRawObject.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/zero_copy/trait.FromRawObject.html...

+ + + \ No newline at end of file diff --git a/uucore/fn.args.html b/uucore/fn.args.html new file mode 100644 index 000000000..9c13e504f --- /dev/null +++ b/uucore/fn.args.html @@ -0,0 +1,3 @@ +args in uucore - Rust + +

Function uucore::args[][src]

pub fn args() -> impl Iterator<Item = String>
\ No newline at end of file diff --git a/uucore/fn.args_os.html b/uucore/fn.args_os.html new file mode 100644 index 000000000..5b983f6e4 --- /dev/null +++ b/uucore/fn.args_os.html @@ -0,0 +1,3 @@ +args_os in uucore - Rust + +

Function uucore::args_os[][src]

pub fn args_os() -> impl Iterator<Item = OsString>
\ No newline at end of file diff --git a/uucore/fn.execution_phrase.html b/uucore/fn.execution_phrase.html new file mode 100644 index 000000000..9bdbfe8a1 --- /dev/null +++ b/uucore/fn.execution_phrase.html @@ -0,0 +1,4 @@ +execution_phrase in uucore - Rust + +

Function uucore::execution_phrase[][src]

pub fn execution_phrase() -> String
Expand description

Derive the complete execution phrase for “usage”.

+
\ No newline at end of file diff --git a/uucore/fn.get_utility_is_second_arg.html b/uucore/fn.get_utility_is_second_arg.html new file mode 100644 index 000000000..69050534b --- /dev/null +++ b/uucore/fn.get_utility_is_second_arg.html @@ -0,0 +1,3 @@ +get_utility_is_second_arg in uucore - Rust + +

Function uucore::get_utility_is_second_arg[][src]

pub fn get_utility_is_second_arg() -> bool
\ No newline at end of file diff --git a/uucore/fn.set_utility_is_second_arg.html b/uucore/fn.set_utility_is_second_arg.html new file mode 100644 index 000000000..bbfbd2340 --- /dev/null +++ b/uucore/fn.set_utility_is_second_arg.html @@ -0,0 +1,3 @@ +set_utility_is_second_arg in uucore - Rust + +

Function uucore::set_utility_is_second_arg[][src]

pub fn set_utility_is_second_arg()
\ No newline at end of file diff --git a/uucore/fn.util_name.html b/uucore/fn.util_name.html new file mode 100644 index 000000000..06c1fbac8 --- /dev/null +++ b/uucore/fn.util_name.html @@ -0,0 +1,4 @@ +util_name in uucore - Rust + +

Function uucore::util_name[][src]

pub fn util_name() -> String
Expand description

Derive the utility name.

+
\ No newline at end of file diff --git a/uucore/fs/enum.MissingHandling.html b/uucore/fs/enum.MissingHandling.html new file mode 100644 index 000000000..b69ab50ef --- /dev/null +++ b/uucore/fs/enum.MissingHandling.html @@ -0,0 +1,32 @@ +MissingHandling in uucore::fs - Rust + +

Enum uucore::fs::MissingHandling[][src]

pub enum MissingHandling {
+    Normal,
+    Existing,
+    Missing,
+}
Expand description

Controls how symbolic links should be handled when canonicalizing a path.

+

+ Variants

+
Normal

Return an error if any part of the path is missing.

+
Existing

Resolve symbolic links, ignoring errors on the final component.

+
Missing

Resolve symbolic links, ignoring errors on the non-final components.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/fs/enum.ResolveMode.html b/uucore/fs/enum.ResolveMode.html new file mode 100644 index 000000000..bf30e7571 --- /dev/null +++ b/uucore/fs/enum.ResolveMode.html @@ -0,0 +1,32 @@ +ResolveMode in uucore::fs - Rust + +

Enum uucore::fs::ResolveMode[][src]

pub enum ResolveMode {
+    None,
+    Physical,
+    Logical,
+}
Expand description

Controls when symbolic links are resolved

+

+ Variants

+
None

Do not resolve any symbolic links.

+
Physical

Resolve symlinks as encountered when processing the path

+
Logical

Resolve ‘..’ elements before symlinks

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/fs/fn.canonicalize.html b/uucore/fs/fn.canonicalize.html new file mode 100644 index 000000000..11dcb7c0c --- /dev/null +++ b/uucore/fs/fn.canonicalize.html @@ -0,0 +1,28 @@ +canonicalize in uucore::fs - Rust + +

Function uucore::fs::canonicalize[][src]

pub fn canonicalize<P: AsRef<Path>>(
    original: P,
    miss_mode: MissingHandling,
    res_mode: ResolveMode
) -> IOResult<PathBuf>
Expand description

Return the canonical, absolute form of a path.

+

This function is a generalization of std::fs::canonicalize that +allows controlling how symbolic links are resolved and how to deal +with missing components. It returns the canonical, absolute form of +a path. +The miss_mode parameter controls how missing path elements are handled

+ +

The res_mode parameter controls how symbolic links are +resolved:

+ +
\ No newline at end of file diff --git a/uucore/fs/fn.display_permissions.html b/uucore/fs/fn.display_permissions.html new file mode 100644 index 000000000..aa262dd72 --- /dev/null +++ b/uucore/fs/fn.display_permissions.html @@ -0,0 +1,3 @@ +display_permissions in uucore::fs - Rust + +

Function uucore::fs::display_permissions[][src]

pub fn display_permissions(
    metadata: &Metadata,
    display_file_type: bool
) -> String
\ No newline at end of file diff --git a/uucore/fs/fn.display_permissions_unix.html b/uucore/fs/fn.display_permissions_unix.html new file mode 100644 index 000000000..d731ab176 --- /dev/null +++ b/uucore/fs/fn.display_permissions_unix.html @@ -0,0 +1,3 @@ +display_permissions_unix in uucore::fs - Rust + +

Function uucore::fs::display_permissions_unix[][src]

pub fn display_permissions_unix(mode: mode_t, display_file_type: bool) -> String
\ No newline at end of file diff --git a/uucore/fs/fn.normalize_path.html b/uucore/fs/fn.normalize_path.html new file mode 100644 index 000000000..d1e6f8876 --- /dev/null +++ b/uucore/fs/fn.normalize_path.html @@ -0,0 +1,3 @@ +normalize_path in uucore::fs - Rust + +

Function uucore::fs::normalize_path[][src]

pub fn normalize_path(path: &Path) -> PathBuf
\ No newline at end of file diff --git a/uucore/fs/fn.resolve_relative_path.html b/uucore/fs/fn.resolve_relative_path.html new file mode 100644 index 000000000..d4cae02d3 --- /dev/null +++ b/uucore/fs/fn.resolve_relative_path.html @@ -0,0 +1,3 @@ +resolve_relative_path in uucore::fs - Rust + +

Function uucore::fs::resolve_relative_path[][src]

pub fn resolve_relative_path(path: &Path) -> Cow<'_, Path>
\ No newline at end of file diff --git a/uucore/fs/index.html b/uucore/fs/index.html new file mode 100644 index 000000000..edafd44c6 --- /dev/null +++ b/uucore/fs/index.html @@ -0,0 +1,8 @@ +uucore::fs - Rust + +

Module uucore::fs[][src]

Enums

+
MissingHandling

Controls how symbolic links should be handled when canonicalizing a path.

+
ResolveMode

Controls when symbolic links are resolved

+

Functions

+
canonicalize

Return the canonical, absolute form of a path.

+
display_permissions
display_permissions_unix
normalize_path
resolve_relative_path
\ No newline at end of file diff --git a/uucore/fs/sidebar-items.js b/uucore/fs/sidebar-items.js new file mode 100644 index 000000000..53b816222 --- /dev/null +++ b/uucore/fs/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["MissingHandling","Controls how symbolic links should be handled when canonicalizing a path."],["ResolveMode","Controls when symbolic links are resolved"]],"fn":[["canonicalize","Return the canonical, absolute form of a path."],["display_permissions",""],["display_permissions_unix",""],["normalize_path",""],["resolve_relative_path",""]]}); \ No newline at end of file diff --git a/uucore/fsext/fn.StatFs.html b/uucore/fsext/fn.StatFs.html new file mode 100644 index 000000000..41a8090a7 --- /dev/null +++ b/uucore/fsext/fn.StatFs.html @@ -0,0 +1,3 @@ +StatFs in uucore::fsext - Rust + +

Function uucore::fsext::StatFs[]

pub unsafe extern "C" fn StatFs(path: *const i8, buf: *mut statfs) -> i32
\ No newline at end of file diff --git a/uucore/fsext/fn.pretty_filetype.html b/uucore/fsext/fn.pretty_filetype.html new file mode 100644 index 000000000..7d32b0cc7 --- /dev/null +++ b/uucore/fsext/fn.pretty_filetype.html @@ -0,0 +1,3 @@ +pretty_filetype in uucore::fsext - Rust + +

Function uucore::fsext::pretty_filetype[][src]

pub fn pretty_filetype<'a>(mode: mode_t, size: u64) -> &'a str
\ No newline at end of file diff --git a/uucore/fsext/fn.pretty_fstype.html b/uucore/fsext/fn.pretty_fstype.html new file mode 100644 index 000000000..694071150 --- /dev/null +++ b/uucore/fsext/fn.pretty_fstype.html @@ -0,0 +1,3 @@ +pretty_fstype in uucore::fsext - Rust + +

Function uucore::fsext::pretty_fstype[][src]

pub fn pretty_fstype<'a>(fstype: i64) -> Cow<'a, str>
\ No newline at end of file diff --git a/uucore/fsext/fn.pretty_time.html b/uucore/fsext/fn.pretty_time.html new file mode 100644 index 000000000..5b4390a95 --- /dev/null +++ b/uucore/fsext/fn.pretty_time.html @@ -0,0 +1,3 @@ +pretty_time in uucore::fsext - Rust + +

Function uucore::fsext::pretty_time[][src]

pub fn pretty_time(sec: i64, nsec: i64) -> String
\ No newline at end of file diff --git a/uucore/fsext/fn.read_fs_list.html b/uucore/fsext/fn.read_fs_list.html new file mode 100644 index 000000000..5f32010e8 --- /dev/null +++ b/uucore/fsext/fn.read_fs_list.html @@ -0,0 +1,4 @@ +read_fs_list in uucore::fsext - Rust + +

Function uucore::fsext::read_fs_list[][src]

pub fn read_fs_list() -> Vec<MountInfo>
Expand description

Read file system list.

+
\ No newline at end of file diff --git a/uucore/fsext/fn.statfs.html b/uucore/fsext/fn.statfs.html new file mode 100644 index 000000000..96a0b9813 --- /dev/null +++ b/uucore/fsext/fn.statfs.html @@ -0,0 +1,3 @@ +statfs in uucore::fsext - Rust + +

Function uucore::fsext::statfs[][src]

pub fn statfs<P: AsRef<Path>>(path: P) -> Result<StatFs, String> where
    Vec<u8>: From<P>, 
\ No newline at end of file diff --git a/uucore/fsext/fn.statfs_fn.html b/uucore/fsext/fn.statfs_fn.html new file mode 100644 index 000000000..2be137f60 --- /dev/null +++ b/uucore/fsext/fn.statfs_fn.html @@ -0,0 +1,3 @@ +statfs_fn in uucore::fsext - Rust + +

Function uucore::fsext::statfs_fn[]

pub unsafe extern "C" fn statfs_fn(path: *const i8, buf: *mut statfs) -> i32
\ No newline at end of file diff --git a/uucore/fsext/index.html b/uucore/fsext/index.html new file mode 100644 index 000000000..a96f04131 --- /dev/null +++ b/uucore/fsext/index.html @@ -0,0 +1,8 @@ +uucore::fsext - Rust + +

Module uucore::fsext[][src]

Re-exports

+
pub use crate::*;

Structs

+
FsUsage
MountInfo
StatFs
statfs_fn

Traits

+
BirthTime
FsMeta

Functions

+
StatFs
pretty_filetype
pretty_fstype
pretty_time
read_fs_list

Read file system list.

+
statfs
statfs_fn
\ No newline at end of file diff --git a/uucore/fsext/sidebar-items.js b/uucore/fsext/sidebar-items.js new file mode 100644 index 000000000..528a8425f --- /dev/null +++ b/uucore/fsext/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["StatFs",""],["pretty_filetype",""],["pretty_fstype",""],["pretty_time",""],["read_fs_list","Read file system list."],["statfs",""],["statfs_fn",""]],"struct":[["FsUsage",""],["MountInfo",""],["StatFs",""],["statfs_fn",""]],"trait":[["BirthTime",""],["FsMeta",""]]}); \ No newline at end of file diff --git a/uucore/fsext/struct.FsUsage.html b/uucore/fsext/struct.FsUsage.html new file mode 100644 index 000000000..491149531 --- /dev/null +++ b/uucore/fsext/struct.FsUsage.html @@ -0,0 +1,28 @@ +FsUsage in uucore::fsext - Rust + +

Struct uucore::fsext::FsUsage[][src]

pub struct FsUsage {
+    pub blocksize: u64,
+    pub blocks: u64,
+    pub bfree: u64,
+    pub bavail: u64,
+    pub bavail_top_bit_set: bool,
+    pub files: u64,
+    pub ffree: u64,
+}

+ Fields

blocksize: u64blocks: u64bfree: u64bavail: u64bavail_top_bit_set: boolfiles: u64ffree: u64

Implementations

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/fsext/struct.MountInfo.html b/uucore/fsext/struct.MountInfo.html new file mode 100644 index 000000000..7d763904d --- /dev/null +++ b/uucore/fsext/struct.MountInfo.html @@ -0,0 +1,29 @@ +MountInfo in uucore::fsext - Rust + +

Struct uucore::fsext::MountInfo[][src]

pub struct MountInfo {
+    pub dev_id: String,
+    pub dev_name: String,
+    pub fs_type: String,
+    pub mount_dir: String,
+    pub mount_option: String,
+    pub mount_root: String,
+    pub remote: bool,
+    pub dummy: bool,
+}

+ Fields

dev_id: Stringdev_name: Stringfs_type: Stringmount_dir: Stringmount_option: Stringmount_root: Stringremote: booldummy: bool

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/fsext/struct.StatFs.html b/uucore/fsext/struct.StatFs.html new file mode 100644 index 000000000..9aeca222e --- /dev/null +++ b/uucore/fsext/struct.StatFs.html @@ -0,0 +1,37 @@ +StatFs in uucore::fsext - Rust + +

Struct uucore::fsext::StatFs[]

#[repr(C)]
pub struct StatFs { + pub f_type: i64, + pub f_bsize: i64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: fsid_t, + pub f_namelen: i64, + pub f_frsize: i64, + // some fields omitted +}

+ Fields

f_type: i64f_bsize: i64f_blocks: u64f_bfree: u64f_bavail: u64f_files: u64f_ffree: u64f_fsid: fsid_tf_namelen: i64f_frsize: i64

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/fsext/struct.statfs_fn.html b/uucore/fsext/struct.statfs_fn.html new file mode 100644 index 000000000..e9ce3221a --- /dev/null +++ b/uucore/fsext/struct.statfs_fn.html @@ -0,0 +1,37 @@ +statfs_fn in uucore::fsext - Rust + +

Struct uucore::fsext::statfs_fn[]

#[repr(C)]
pub struct statfs_fn { + pub f_type: i64, + pub f_bsize: i64, + pub f_blocks: u64, + pub f_bfree: u64, + pub f_bavail: u64, + pub f_files: u64, + pub f_ffree: u64, + pub f_fsid: fsid_t, + pub f_namelen: i64, + pub f_frsize: i64, + // some fields omitted +}

+ Fields

f_type: i64f_bsize: i64f_blocks: u64f_bfree: u64f_bavail: u64f_files: u64f_ffree: u64f_fsid: fsid_tf_namelen: i64f_frsize: i64

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Feeds this value into the given Hasher. Read more

+

Feeds a slice of this type into the given Hasher. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/fsext/trait.BirthTime.html b/uucore/fsext/trait.BirthTime.html new file mode 100644 index 000000000..ad3431b49 --- /dev/null +++ b/uucore/fsext/trait.BirthTime.html @@ -0,0 +1,6 @@ +BirthTime in uucore::fsext - Rust + +

Trait uucore::fsext::BirthTime[][src]

pub trait BirthTime {
+    fn pretty_birth(&self) -> String;
+
fn birth(&self) -> String; +}

Required methods

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/uucore/fsext/trait.FsMeta.html b/uucore/fsext/trait.FsMeta.html new file mode 100644 index 000000000..e7b915493 --- /dev/null +++ b/uucore/fsext/trait.FsMeta.html @@ -0,0 +1,14 @@ +FsMeta in uucore::fsext - Rust + +

Trait uucore::fsext::FsMeta[][src]

pub trait FsMeta {
+    fn fs_type(&self) -> i64;
+
fn io_size(&self) -> u64; +
fn block_size(&self) -> i64; +
fn total_blocks(&self) -> u64; +
fn free_blocks(&self) -> u64; +
fn avail_blocks(&self) -> u64; +
fn total_file_nodes(&self) -> u64; +
fn free_file_nodes(&self) -> u64; +
fn fsid(&self) -> u64; +
fn namelen(&self) -> u64; +}

Required methods

Implementors

\ No newline at end of file diff --git a/uucore/index.html b/uucore/index.html new file mode 100644 index 000000000..b5b0c50ce --- /dev/null +++ b/uucore/index.html @@ -0,0 +1,28 @@ +uucore - Rust + +

Crate uucore[][src]

Re-exports

+
pub extern crate libc;

Modules

+
backup_control
coreopts
encoding
entries

Get password/group file entry

+
error

All utils return exit with an exit code. Usually, the following scheme is used:

+
fs
fsext
mode
os
panic
parse_size
parse_time
perms
process
ranges
ringbuffer

A fixed-size ring buffer.

+
signals
utmpx

Aims to provide platform-independent methods to obtain login records

+
version_cmp
zero_copy

Macros

+
app
crash

Display the provided error message, then exit() with the provided exit code

+
crash_if_err

Unwraps the Result. Instead of panicking, it exists the program with the +provided exit code.

+
exit

Calls exit() with the provided exit code.

+
has
msg_expects_no_more_than_one_of
msg_expects_one_of
msg_invalid_input
msg_invalid_opt_use
msg_opt_invalid_should_be
msg_opt_only_usable_if
return_if_err

Unwraps the Result. Instead of panicking, it shows the error and then +returns from the function with the provided exit code. +Assumes the current function returns an i32 value.

+
safe_unwrap

Unwraps the Result. Instead of panicking, it exists the program with exit +code 1.

+
safe_write
safe_writeln
show
show_error

Show an error to stderr in a similar style to GNU coreutils.

+
show_error_custom_description

Show a warning to stderr in a similar style to GNU coreutils.

+
show_if_err
show_usage_error

Show a bad invocation help message in a similar style to GNU coreutils.

+
show_warning
snippet_list_join
snippet_list_join_oxford_comma
uio_error

Shorthand to construct UIoError-instances.

+

Enums

+
ConversionResult
InvalidEncodingHandling

Traits

+
Args

Functions

+
args
args_os
execution_phrase

Derive the complete execution phrase for “usage”.

+
get_utility_is_second_arg
set_utility_is_second_arg
util_name

Derive the utility name.

+
\ No newline at end of file diff --git a/uucore/macro.app!.html b/uucore/macro.app!.html new file mode 100644 index 000000000..8f4cfb61b --- /dev/null +++ b/uucore/macro.app!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.app.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.app.html b/uucore/macro.app.html new file mode 100644 index 000000000..e45a79623 --- /dev/null +++ b/uucore/macro.app.html @@ -0,0 +1,8 @@ +app in uucore - Rust + +

Macro uucore::app[][src]

+macro_rules! app {
+    ($syntax: expr, $summary: expr, $long_help: expr) => { ... };
+    ($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.crash!.html b/uucore/macro.crash!.html new file mode 100644 index 000000000..568fcb67a --- /dev/null +++ b/uucore/macro.crash!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.crash.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.crash.html b/uucore/macro.crash.html new file mode 100644 index 000000000..3fa66be9b --- /dev/null +++ b/uucore/macro.crash.html @@ -0,0 +1,8 @@ +crash in uucore - Rust + +

Macro uucore::crash[][src]

+macro_rules! crash {
+    ($exit_code:expr, $($args:tt)+) => { ... };
+}
+
Expand description

Display the provided error message, then exit() with the provided exit code

+
\ No newline at end of file diff --git a/uucore/macro.crash_if_err!.html b/uucore/macro.crash_if_err!.html new file mode 100644 index 000000000..1d7e6274f --- /dev/null +++ b/uucore/macro.crash_if_err!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.crash_if_err.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.crash_if_err.html b/uucore/macro.crash_if_err.html new file mode 100644 index 000000000..faed8993a --- /dev/null +++ b/uucore/macro.crash_if_err.html @@ -0,0 +1,9 @@ +crash_if_err in uucore - Rust + +

Macro uucore::crash_if_err[][src]

+macro_rules! crash_if_err {
+    ($exit_code:expr, $exp:expr) => { ... };
+}
+
Expand description

Unwraps the Result. Instead of panicking, it exists the program with the +provided exit code.

+
\ No newline at end of file diff --git a/uucore/macro.exit!.html b/uucore/macro.exit!.html new file mode 100644 index 000000000..2c9b3ab88 --- /dev/null +++ b/uucore/macro.exit!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.exit.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.exit.html b/uucore/macro.exit.html new file mode 100644 index 000000000..8b5c7b770 --- /dev/null +++ b/uucore/macro.exit.html @@ -0,0 +1,8 @@ +exit in uucore - Rust + +

Macro uucore::exit[][src]

+macro_rules! exit {
+    ($exit_code:expr) => { ... };
+}
+
Expand description

Calls exit() with the provided exit code.

+
\ No newline at end of file diff --git a/uucore/macro.has!.html b/uucore/macro.has!.html new file mode 100644 index 000000000..a69015b17 --- /dev/null +++ b/uucore/macro.has!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.has.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.has.html b/uucore/macro.has.html new file mode 100644 index 000000000..58b4313de --- /dev/null +++ b/uucore/macro.has.html @@ -0,0 +1,7 @@ +has in uucore - Rust + +

Macro uucore::has[][src]

+macro_rules! has {
+    ($mode:expr, $perm:expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.msg_expects_no_more_than_one_of!.html b/uucore/macro.msg_expects_no_more_than_one_of!.html new file mode 100644 index 000000000..067966d31 --- /dev/null +++ b/uucore/macro.msg_expects_no_more_than_one_of!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.msg_expects_no_more_than_one_of.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.msg_expects_no_more_than_one_of.html b/uucore/macro.msg_expects_no_more_than_one_of.html new file mode 100644 index 000000000..5f8adb59a --- /dev/null +++ b/uucore/macro.msg_expects_no_more_than_one_of.html @@ -0,0 +1,7 @@ +msg_expects_no_more_than_one_of in uucore - Rust + +

Macro uucore::msg_expects_no_more_than_one_of[][src]

+macro_rules! msg_expects_no_more_than_one_of {
+    ($valOne:expr $(, $remaining_values:expr)*) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.msg_expects_one_of!.html b/uucore/macro.msg_expects_one_of!.html new file mode 100644 index 000000000..8342a8a33 --- /dev/null +++ b/uucore/macro.msg_expects_one_of!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.msg_expects_one_of.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.msg_expects_one_of.html b/uucore/macro.msg_expects_one_of.html new file mode 100644 index 000000000..60408faf3 --- /dev/null +++ b/uucore/macro.msg_expects_one_of.html @@ -0,0 +1,7 @@ +msg_expects_one_of in uucore - Rust + +

Macro uucore::msg_expects_one_of[][src]

+macro_rules! msg_expects_one_of {
+    ($valOne:expr $(, $remaining_values:expr)*) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.msg_invalid_input!.html b/uucore/macro.msg_invalid_input!.html new file mode 100644 index 000000000..7794b2b64 --- /dev/null +++ b/uucore/macro.msg_invalid_input!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.msg_invalid_input.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.msg_invalid_input.html b/uucore/macro.msg_invalid_input.html new file mode 100644 index 000000000..fd575b4c8 --- /dev/null +++ b/uucore/macro.msg_invalid_input.html @@ -0,0 +1,7 @@ +msg_invalid_input in uucore - Rust + +

Macro uucore::msg_invalid_input[][src]

+macro_rules! msg_invalid_input {
+    ($reason: expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.msg_invalid_opt_use!.html b/uucore/macro.msg_invalid_opt_use!.html new file mode 100644 index 000000000..17f6477b5 --- /dev/null +++ b/uucore/macro.msg_invalid_opt_use!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.msg_invalid_opt_use.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.msg_invalid_opt_use.html b/uucore/macro.msg_invalid_opt_use.html new file mode 100644 index 000000000..48b8a430f --- /dev/null +++ b/uucore/macro.msg_invalid_opt_use.html @@ -0,0 +1,8 @@ +msg_invalid_opt_use in uucore - Rust + +

Macro uucore::msg_invalid_opt_use[][src]

+macro_rules! msg_invalid_opt_use {
+    ($about:expr, $flag:expr) => { ... };
+    ($about:expr, $long_flag:expr, $short_flag:expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.msg_opt_invalid_should_be!.html b/uucore/macro.msg_opt_invalid_should_be!.html new file mode 100644 index 000000000..7cdf37b58 --- /dev/null +++ b/uucore/macro.msg_opt_invalid_should_be!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.msg_opt_invalid_should_be.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.msg_opt_invalid_should_be.html b/uucore/macro.msg_opt_invalid_should_be.html new file mode 100644 index 000000000..d90918a79 --- /dev/null +++ b/uucore/macro.msg_opt_invalid_should_be.html @@ -0,0 +1,8 @@ +msg_opt_invalid_should_be in uucore - Rust + +

Macro uucore::msg_opt_invalid_should_be[][src]

+macro_rules! msg_opt_invalid_should_be {
+    ($expects:expr, $received:expr, $flag:expr) => { ... };
+    ($expects:expr, $received:expr, $long_flag:expr, $short_flag:expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.msg_opt_only_usable_if!.html b/uucore/macro.msg_opt_only_usable_if!.html new file mode 100644 index 000000000..eacfce632 --- /dev/null +++ b/uucore/macro.msg_opt_only_usable_if!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.msg_opt_only_usable_if.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.msg_opt_only_usable_if.html b/uucore/macro.msg_opt_only_usable_if.html new file mode 100644 index 000000000..9e88f0298 --- /dev/null +++ b/uucore/macro.msg_opt_only_usable_if.html @@ -0,0 +1,8 @@ +msg_opt_only_usable_if in uucore - Rust + +

Macro uucore::msg_opt_only_usable_if[][src]

+macro_rules! msg_opt_only_usable_if {
+    ($clause:expr, $flag:expr) => { ... };
+    ($clause:expr, $long_flag:expr, $short_flag:expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.return_if_err!.html b/uucore/macro.return_if_err!.html new file mode 100644 index 000000000..1f4e67d5b --- /dev/null +++ b/uucore/macro.return_if_err!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.return_if_err.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.return_if_err.html b/uucore/macro.return_if_err.html new file mode 100644 index 000000000..6eed6b3da --- /dev/null +++ b/uucore/macro.return_if_err.html @@ -0,0 +1,10 @@ +return_if_err in uucore - Rust + +

Macro uucore::return_if_err[][src]

+macro_rules! return_if_err {
+    ($exit_code:expr, $exp:expr) => { ... };
+}
+
Expand description

Unwraps the Result. Instead of panicking, it shows the error and then +returns from the function with the provided exit code. +Assumes the current function returns an i32 value.

+
\ No newline at end of file diff --git a/uucore/macro.safe_unwrap!.html b/uucore/macro.safe_unwrap!.html new file mode 100644 index 000000000..ab299efaa --- /dev/null +++ b/uucore/macro.safe_unwrap!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.safe_unwrap.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.safe_unwrap.html b/uucore/macro.safe_unwrap.html new file mode 100644 index 000000000..32d0e9856 --- /dev/null +++ b/uucore/macro.safe_unwrap.html @@ -0,0 +1,9 @@ +safe_unwrap in uucore - Rust + +

Macro uucore::safe_unwrap[][src]

+macro_rules! safe_unwrap {
+    ($exp:expr) => { ... };
+}
+
Expand description

Unwraps the Result. Instead of panicking, it exists the program with exit +code 1.

+
\ No newline at end of file diff --git a/uucore/macro.safe_write!.html b/uucore/macro.safe_write!.html new file mode 100644 index 000000000..3ee13d501 --- /dev/null +++ b/uucore/macro.safe_write!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.safe_write.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.safe_write.html b/uucore/macro.safe_write.html new file mode 100644 index 000000000..fb2f19616 --- /dev/null +++ b/uucore/macro.safe_write.html @@ -0,0 +1,7 @@ +safe_write in uucore - Rust + +

Macro uucore::safe_write[][src]

+macro_rules! safe_write {
+    ($fd:expr, $($args:tt)+) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.safe_writeln!.html b/uucore/macro.safe_writeln!.html new file mode 100644 index 000000000..d1805acc7 --- /dev/null +++ b/uucore/macro.safe_writeln!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.safe_writeln.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.safe_writeln.html b/uucore/macro.safe_writeln.html new file mode 100644 index 000000000..bf68cb080 --- /dev/null +++ b/uucore/macro.safe_writeln.html @@ -0,0 +1,7 @@ +safe_writeln in uucore - Rust + +

Macro uucore::safe_writeln[][src]

+macro_rules! safe_writeln {
+    ($fd:expr, $($args:tt)+) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.show!.html b/uucore/macro.show!.html new file mode 100644 index 000000000..bb5cc3235 --- /dev/null +++ b/uucore/macro.show!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.show.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.show.html b/uucore/macro.show.html new file mode 100644 index 000000000..cd2dc2e8e --- /dev/null +++ b/uucore/macro.show.html @@ -0,0 +1,7 @@ +show in uucore - Rust + +

Macro uucore::show[][src]

+macro_rules! show {
+    ($err:expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.show_error!.html b/uucore/macro.show_error!.html new file mode 100644 index 000000000..697242dd3 --- /dev/null +++ b/uucore/macro.show_error!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.show_error.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.show_error.html b/uucore/macro.show_error.html new file mode 100644 index 000000000..4be2d5b3b --- /dev/null +++ b/uucore/macro.show_error.html @@ -0,0 +1,8 @@ +show_error in uucore - Rust + +

Macro uucore::show_error[][src]

+macro_rules! show_error {
+    ($($args:tt)+) => { ... };
+}
+
Expand description

Show an error to stderr in a similar style to GNU coreutils.

+
\ No newline at end of file diff --git a/uucore/macro.show_error_custom_description!.html b/uucore/macro.show_error_custom_description!.html new file mode 100644 index 000000000..19893c824 --- /dev/null +++ b/uucore/macro.show_error_custom_description!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.show_error_custom_description.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.show_error_custom_description.html b/uucore/macro.show_error_custom_description.html new file mode 100644 index 000000000..26e777454 --- /dev/null +++ b/uucore/macro.show_error_custom_description.html @@ -0,0 +1,8 @@ +show_error_custom_description in uucore - Rust + +

Macro uucore::show_error_custom_description[][src]

+macro_rules! show_error_custom_description {
+    ($err:expr,$($args:tt)+) => { ... };
+}
+
Expand description

Show a warning to stderr in a similar style to GNU coreutils.

+
\ No newline at end of file diff --git a/uucore/macro.show_if_err!.html b/uucore/macro.show_if_err!.html new file mode 100644 index 000000000..32ddd8c57 --- /dev/null +++ b/uucore/macro.show_if_err!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.show_if_err.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.show_if_err.html b/uucore/macro.show_if_err.html new file mode 100644 index 000000000..46f059617 --- /dev/null +++ b/uucore/macro.show_if_err.html @@ -0,0 +1,7 @@ +show_if_err in uucore - Rust + +

Macro uucore::show_if_err[][src]

+macro_rules! show_if_err {
+    ($res:expr) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.show_usage_error!.html b/uucore/macro.show_usage_error!.html new file mode 100644 index 000000000..d49b8be25 --- /dev/null +++ b/uucore/macro.show_usage_error!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.show_usage_error.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.show_usage_error.html b/uucore/macro.show_usage_error.html new file mode 100644 index 000000000..33254b1e5 --- /dev/null +++ b/uucore/macro.show_usage_error.html @@ -0,0 +1,8 @@ +show_usage_error in uucore - Rust + +

Macro uucore::show_usage_error[][src]

+macro_rules! show_usage_error {
+    ($($args:tt)+) => { ... };
+}
+
Expand description

Show a bad invocation help message in a similar style to GNU coreutils.

+
\ No newline at end of file diff --git a/uucore/macro.show_warning!.html b/uucore/macro.show_warning!.html new file mode 100644 index 000000000..c47251a43 --- /dev/null +++ b/uucore/macro.show_warning!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.show_warning.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.show_warning.html b/uucore/macro.show_warning.html new file mode 100644 index 000000000..9f1cb53e8 --- /dev/null +++ b/uucore/macro.show_warning.html @@ -0,0 +1,7 @@ +show_warning in uucore - Rust + +

Macro uucore::show_warning[][src]

+macro_rules! show_warning {
+    ($($args:tt)+) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.snippet_list_join!.html b/uucore/macro.snippet_list_join!.html new file mode 100644 index 000000000..ed7fcc510 --- /dev/null +++ b/uucore/macro.snippet_list_join!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.snippet_list_join.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.snippet_list_join.html b/uucore/macro.snippet_list_join.html new file mode 100644 index 000000000..787d99d7b --- /dev/null +++ b/uucore/macro.snippet_list_join.html @@ -0,0 +1,8 @@ +snippet_list_join in uucore - Rust + +

Macro uucore::snippet_list_join[][src]

+macro_rules! snippet_list_join {
+    ($conjunction:expr, $valOne:expr, $valTwo:expr) => { ... };
+    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.snippet_list_join_oxford_comma!.html b/uucore/macro.snippet_list_join_oxford_comma!.html new file mode 100644 index 000000000..2f2cdea86 --- /dev/null +++ b/uucore/macro.snippet_list_join_oxford_comma!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.snippet_list_join_oxford_comma.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.snippet_list_join_oxford_comma.html b/uucore/macro.snippet_list_join_oxford_comma.html new file mode 100644 index 000000000..244739959 --- /dev/null +++ b/uucore/macro.snippet_list_join_oxford_comma.html @@ -0,0 +1,8 @@ +snippet_list_join_oxford_comma in uucore - Rust + +

Macro uucore::snippet_list_join_oxford_comma[][src]

+macro_rules! snippet_list_join_oxford_comma {
+    ($conjunction:expr, $valOne:expr, $valTwo:expr) => { ... };
+    ($conjunction:expr, $valOne:expr, $valTwo:expr $(, $remaining_values:expr)*) => { ... };
+}
+
\ No newline at end of file diff --git a/uucore/macro.uio_error!.html b/uucore/macro.uio_error!.html new file mode 100644 index 000000000..6e7fc9fa5 --- /dev/null +++ b/uucore/macro.uio_error!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.uio_error.html...

+ + + \ No newline at end of file diff --git a/uucore/macro.uio_error.html b/uucore/macro.uio_error.html new file mode 100644 index 000000000..9c71c6198 --- /dev/null +++ b/uucore/macro.uio_error.html @@ -0,0 +1,56 @@ +uio_error in uucore - Rust + +

Macro uucore::uio_error[][src]

+macro_rules! uio_error {
+    ($err:expr, $($args:tt)+) => { ... };
+}
+
Expand description

Shorthand to construct UIoError-instances.

+

This macro serves as a convenience call to quickly construct instances of +UIoError. It takes:

+
    +
  • An instance of std::io::Error
  • +
  • A format!-compatible string and
  • +
  • An arbitrary number of arguments to the format string
  • +
+

In exactly this order. It is equivalent to the more verbose code seen in the +example.

+

Examples

+
+use uucore::error::UIoError;
+use uucore::uio_error;
+
+let io_err = std::io::Error::new(
+    std::io::ErrorKind::PermissionDenied, "fix me please!"
+);
+
+let uio_err = UIoError::new(
+    io_err.kind(),
+    format!("Error code: {}", 2)
+);
+
+let other_uio_err = uio_error!(io_err, "Error code: {}", 2);
+
+// prints "fix me please!: Permission denied"
+println!("{}", uio_err);
+// prints "Error code: 2: Permission denied"
+println!("{}", other_uio_err);
+

The std::fmt::Display impl of UIoError will then ensure that an +appropriate error message relating to the actual error kind of the +std::io::Error is appended to whatever error message is defined in +addition (as secondary argument).

+

If you want to show only the error message for the std::io::ErrorKind +that’s contained in UIoError, pass the second argument as empty string:

+ +
+use uucore::error::UIoError;
+use uucore::uio_error;
+
+let io_err = std::io::Error::new(
+    std::io::ErrorKind::PermissionDenied, "fix me please!"
+);
+
+let other_uio_err = uio_error!(io_err, "");
+
+// prints: ": Permission denied"
+println!("{}", other_uio_err);
+
\ No newline at end of file diff --git a/uucore/mode/fn.parse_mode.html b/uucore/mode/fn.parse_mode.html new file mode 100644 index 000000000..e98a34ff5 --- /dev/null +++ b/uucore/mode/fn.parse_mode.html @@ -0,0 +1,3 @@ +parse_mode in uucore::mode - Rust + +

Function uucore::mode::parse_mode[][src]

pub fn parse_mode(mode: &str) -> Result<mode_t, String>
\ No newline at end of file diff --git a/uucore/mode/fn.parse_numeric.html b/uucore/mode/fn.parse_numeric.html new file mode 100644 index 000000000..575cce36d --- /dev/null +++ b/uucore/mode/fn.parse_numeric.html @@ -0,0 +1,3 @@ +parse_numeric in uucore::mode - Rust + +

Function uucore::mode::parse_numeric[][src]

pub fn parse_numeric(fperm: u32, mode: &str) -> Result<u32, String>
\ No newline at end of file diff --git a/uucore/mode/fn.parse_symbolic.html b/uucore/mode/fn.parse_symbolic.html new file mode 100644 index 000000000..91727dd8a --- /dev/null +++ b/uucore/mode/fn.parse_symbolic.html @@ -0,0 +1,3 @@ +parse_symbolic in uucore::mode - Rust + +

Function uucore::mode::parse_symbolic[][src]

pub fn parse_symbolic(
    fperm: u32,
    mode: &str,
    considering_dir: bool
) -> Result<u32, String>
\ No newline at end of file diff --git a/uucore/mode/index.html b/uucore/mode/index.html new file mode 100644 index 000000000..e900717f6 --- /dev/null +++ b/uucore/mode/index.html @@ -0,0 +1,4 @@ +uucore::mode - Rust + +

Module uucore::mode[][src]

Functions

+
parse_mode
parse_numeric
parse_symbolic
\ No newline at end of file diff --git a/uucore/mode/sidebar-items.js b/uucore/mode/sidebar-items.js new file mode 100644 index 000000000..07c2f355e --- /dev/null +++ b/uucore/mode/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["parse_mode",""],["parse_numeric",""],["parse_symbolic",""]]}); \ No newline at end of file diff --git a/uucore/mods/backup_control/enum.BackupMode.html b/uucore/mods/backup_control/enum.BackupMode.html new file mode 100644 index 000000000..8900c0811 --- /dev/null +++ b/uucore/mods/backup_control/enum.BackupMode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/enum.BackupMode.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/backup_control/fn.determine_backup_mode.html b/uucore/mods/backup_control/fn.determine_backup_mode.html new file mode 100644 index 000000000..df1af6cd6 --- /dev/null +++ b/uucore/mods/backup_control/fn.determine_backup_mode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/fn.determine_backup_mode.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/backup_control/fn.determine_backup_suffix.html b/uucore/mods/backup_control/fn.determine_backup_suffix.html new file mode 100644 index 000000000..ed1bee620 --- /dev/null +++ b/uucore/mods/backup_control/fn.determine_backup_suffix.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/fn.determine_backup_suffix.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/backup_control/fn.get_backup_path.html b/uucore/mods/backup_control/fn.get_backup_path.html new file mode 100644 index 000000000..0deee334b --- /dev/null +++ b/uucore/mods/backup_control/fn.get_backup_path.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/fn.get_backup_path.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/backup_control/index.html b/uucore/mods/backup_control/index.html new file mode 100644 index 000000000..a2b404ca4 --- /dev/null +++ b/uucore/mods/backup_control/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/index.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/backup_control/static.BACKUP_CONTROL_LONG_HELP.html b/uucore/mods/backup_control/static.BACKUP_CONTROL_LONG_HELP.html new file mode 100644 index 000000000..6046a3f84 --- /dev/null +++ b/uucore/mods/backup_control/static.BACKUP_CONTROL_LONG_HELP.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/static.BACKUP_CONTROL_LONG_HELP.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/backup_control/static.BACKUP_CONTROL_VALUES.html b/uucore/mods/backup_control/static.BACKUP_CONTROL_VALUES.html new file mode 100644 index 000000000..3a01e2909 --- /dev/null +++ b/uucore/mods/backup_control/static.BACKUP_CONTROL_VALUES.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/backup_control/static.BACKUP_CONTROL_VALUES.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/coreopts/index.html b/uucore/mods/coreopts/index.html new file mode 100644 index 000000000..7ebe7fd64 --- /dev/null +++ b/uucore/mods/coreopts/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/coreopts/index.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/coreopts/struct.CoreOptions.html b/uucore/mods/coreopts/struct.CoreOptions.html new file mode 100644 index 000000000..e3a9889d5 --- /dev/null +++ b/uucore/mods/coreopts/struct.CoreOptions.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/coreopts/struct.CoreOptions.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/coreopts/struct.HelpText.html b/uucore/mods/coreopts/struct.HelpText.html new file mode 100644 index 000000000..c12a36635 --- /dev/null +++ b/uucore/mods/coreopts/struct.HelpText.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/coreopts/struct.HelpText.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/fn.get_exit_code.html b/uucore/mods/error/fn.get_exit_code.html new file mode 100644 index 000000000..4000fab39 --- /dev/null +++ b/uucore/mods/error/fn.get_exit_code.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/fn.get_exit_code.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/fn.set_exit_code.html b/uucore/mods/error/fn.set_exit_code.html new file mode 100644 index 000000000..185af1485 --- /dev/null +++ b/uucore/mods/error/fn.set_exit_code.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/fn.set_exit_code.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/index.html b/uucore/mods/error/index.html new file mode 100644 index 000000000..a2e10f173 --- /dev/null +++ b/uucore/mods/error/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/index.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/struct.ExitCode.html b/uucore/mods/error/struct.ExitCode.html new file mode 100644 index 000000000..c0de249bf --- /dev/null +++ b/uucore/mods/error/struct.ExitCode.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/struct.ExitCode.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/struct.UIoError.html b/uucore/mods/error/struct.UIoError.html new file mode 100644 index 000000000..eda01256e --- /dev/null +++ b/uucore/mods/error/struct.UIoError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/struct.UIoError.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/struct.USimpleError.html b/uucore/mods/error/struct.USimpleError.html new file mode 100644 index 000000000..2c4f24d18 --- /dev/null +++ b/uucore/mods/error/struct.USimpleError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/struct.USimpleError.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/struct.UUsageError.html b/uucore/mods/error/struct.UUsageError.html new file mode 100644 index 000000000..f190feaab --- /dev/null +++ b/uucore/mods/error/struct.UUsageError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/struct.UUsageError.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/trait.FromIo.html b/uucore/mods/error/trait.FromIo.html new file mode 100644 index 000000000..1ea037c10 --- /dev/null +++ b/uucore/mods/error/trait.FromIo.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/trait.FromIo.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/trait.UError.html b/uucore/mods/error/trait.UError.html new file mode 100644 index 000000000..dc34b8240 --- /dev/null +++ b/uucore/mods/error/trait.UError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/trait.UError.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/error/type.UResult.html b/uucore/mods/error/type.UResult.html new file mode 100644 index 000000000..2571350d0 --- /dev/null +++ b/uucore/mods/error/type.UResult.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/error/type.UResult.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/os/fn.is_wsl_1.html b/uucore/mods/os/fn.is_wsl_1.html new file mode 100644 index 000000000..55dabfeca --- /dev/null +++ b/uucore/mods/os/fn.is_wsl_1.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/os/fn.is_wsl_1.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/os/fn.is_wsl_2.html b/uucore/mods/os/fn.is_wsl_2.html new file mode 100644 index 000000000..d64caa06c --- /dev/null +++ b/uucore/mods/os/fn.is_wsl_2.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/os/fn.is_wsl_2.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/os/index.html b/uucore/mods/os/index.html new file mode 100644 index 000000000..d3d2d8e44 --- /dev/null +++ b/uucore/mods/os/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/os/index.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/panic/fn.mute_sigpipe_panic.html b/uucore/mods/panic/fn.mute_sigpipe_panic.html new file mode 100644 index 000000000..9fb938615 --- /dev/null +++ b/uucore/mods/panic/fn.mute_sigpipe_panic.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/panic/fn.mute_sigpipe_panic.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/panic/index.html b/uucore/mods/panic/index.html new file mode 100644 index 000000000..40843c5c3 --- /dev/null +++ b/uucore/mods/panic/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/panic/index.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/ranges/fn.complement.html b/uucore/mods/ranges/fn.complement.html new file mode 100644 index 000000000..d44c3f075 --- /dev/null +++ b/uucore/mods/ranges/fn.complement.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/ranges/fn.complement.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/ranges/fn.contain.html b/uucore/mods/ranges/fn.contain.html new file mode 100644 index 000000000..4f38bf25b --- /dev/null +++ b/uucore/mods/ranges/fn.contain.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/ranges/fn.contain.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/ranges/index.html b/uucore/mods/ranges/index.html new file mode 100644 index 000000000..6e2dc3107 --- /dev/null +++ b/uucore/mods/ranges/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/ranges/index.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/ranges/struct.Range.html b/uucore/mods/ranges/struct.Range.html new file mode 100644 index 000000000..8483cb75e --- /dev/null +++ b/uucore/mods/ranges/struct.Range.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/ranges/struct.Range.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/version_cmp/fn.version_cmp.html b/uucore/mods/version_cmp/fn.version_cmp.html new file mode 100644 index 000000000..30aa9a79e --- /dev/null +++ b/uucore/mods/version_cmp/fn.version_cmp.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/version_cmp/fn.version_cmp.html...

+ + + \ No newline at end of file diff --git a/uucore/mods/version_cmp/index.html b/uucore/mods/version_cmp/index.html new file mode 100644 index 000000000..988351405 --- /dev/null +++ b/uucore/mods/version_cmp/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/version_cmp/index.html...

+ + + \ No newline at end of file diff --git a/uucore/os/fn.is_wsl_1.html b/uucore/os/fn.is_wsl_1.html new file mode 100644 index 000000000..2baa302b6 --- /dev/null +++ b/uucore/os/fn.is_wsl_1.html @@ -0,0 +1,4 @@ +is_wsl_1 in uucore::os - Rust + +

Function uucore::os::is_wsl_1[][src]

pub fn is_wsl_1() -> bool
Expand description

Test if the program is running under WSL

+
\ No newline at end of file diff --git a/uucore/os/fn.is_wsl_2.html b/uucore/os/fn.is_wsl_2.html new file mode 100644 index 000000000..faa89714e --- /dev/null +++ b/uucore/os/fn.is_wsl_2.html @@ -0,0 +1,3 @@ +is_wsl_2 in uucore::os - Rust + +

Function uucore::os::is_wsl_2[][src]

pub fn is_wsl_2() -> bool
\ No newline at end of file diff --git a/uucore/os/index.html b/uucore/os/index.html new file mode 100644 index 000000000..12a77a198 --- /dev/null +++ b/uucore/os/index.html @@ -0,0 +1,5 @@ +uucore::os - Rust + +

Module uucore::os[][src]

Functions

+
is_wsl_1

Test if the program is running under WSL

+
is_wsl_2
\ No newline at end of file diff --git a/uucore/os/sidebar-items.js b/uucore/os/sidebar-items.js new file mode 100644 index 000000000..9b9b188e5 --- /dev/null +++ b/uucore/os/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["is_wsl_1","Test if the program is running under WSL"],["is_wsl_2",""]]}); \ No newline at end of file diff --git a/uucore/panic/fn.mute_sigpipe_panic.html b/uucore/panic/fn.mute_sigpipe_panic.html new file mode 100644 index 000000000..8aa741243 --- /dev/null +++ b/uucore/panic/fn.mute_sigpipe_panic.html @@ -0,0 +1,3 @@ +mute_sigpipe_panic in uucore::panic - Rust + +

Function uucore::panic::mute_sigpipe_panic[][src]

pub fn mute_sigpipe_panic()
\ No newline at end of file diff --git a/uucore/panic/index.html b/uucore/panic/index.html new file mode 100644 index 000000000..ab143654c --- /dev/null +++ b/uucore/panic/index.html @@ -0,0 +1,4 @@ +uucore::panic - Rust + +

Module uucore::panic[][src]

Functions

+
mute_sigpipe_panic
\ No newline at end of file diff --git a/uucore/panic/sidebar-items.js b/uucore/panic/sidebar-items.js new file mode 100644 index 000000000..1d31fa730 --- /dev/null +++ b/uucore/panic/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["mute_sigpipe_panic",""]]}); \ No newline at end of file diff --git a/uucore/parse_size/enum.ParseSizeError.html b/uucore/parse_size/enum.ParseSizeError.html new file mode 100644 index 000000000..dd7474ab3 --- /dev/null +++ b/uucore/parse_size/enum.ParseSizeError.html @@ -0,0 +1,27 @@ +ParseSizeError in uucore::parse_size - Rust + +

Enum uucore::parse_size::ParseSizeError[][src]

pub enum ParseSizeError {
+    ParseFailure(String),
+    SizeTooBig(String),
+}

+ Variants

+
ParseFailure(String)
SizeTooBig(String)

Trait Implementations

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+
👎 Deprecated since 1.42.0:

use the Display impl or to_string()

+

The lower-level source of this error, if any. Read more

+
🔬 This is a nightly-only experimental API. (backtrace)

Returns a stack backtrace, if available, of where this error occurred. Read more

+
👎 Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/parse_size/fn.parse_size.html b/uucore/parse_size/fn.parse_size.html new file mode 100644 index 000000000..2be5130d6 --- /dev/null +++ b/uucore/parse_size/fn.parse_size.html @@ -0,0 +1,19 @@ +parse_size in uucore::parse_size - Rust + +

Function uucore::parse_size::parse_size[][src]

pub fn parse_size(size: &str) -> Result<usize, ParseSizeError>
Expand description

Parse a size string into a number of bytes.

+

A size string comprises an integer and an optional unit. The unit +may be K, M, G, T, P, E, Z or Y (powers of 1024), or KB, MB, +etc. (powers of 1000), or b which is 512. +Binary prefixes can be used, too: KiB=K, MiB=M, and so on.

+

Errors

+

Will return ParseSizeError if it’s not possible to parse this +string into a number, e.g. if the string does not begin with a +numeral, or if the unit is not one of the supported units described +in the preceding section.

+

Examples

+
+use uucore::parse_size::parse_size;
+assert_eq!(Ok(123), parse_size("123"));
+assert_eq!(Ok(9 * 1000), parse_size("9kB")); // kB is 1000
+assert_eq!(Ok(2 * 1024), parse_size("2K")); // K is 1024
+
\ No newline at end of file diff --git a/uucore/parse_size/index.html b/uucore/parse_size/index.html new file mode 100644 index 000000000..529772e6f --- /dev/null +++ b/uucore/parse_size/index.html @@ -0,0 +1,6 @@ +uucore::parse_size - Rust + +

Module uucore::parse_size[][src]

Enums

+
ParseSizeError

Functions

+
parse_size

Parse a size string into a number of bytes.

+
\ No newline at end of file diff --git a/uucore/parse_size/sidebar-items.js b/uucore/parse_size/sidebar-items.js new file mode 100644 index 000000000..3aa91d3c0 --- /dev/null +++ b/uucore/parse_size/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["ParseSizeError",""]],"fn":[["parse_size","Parse a size string into a number of bytes."]]}); \ No newline at end of file diff --git a/uucore/parse_time/fn.from_str.html b/uucore/parse_time/fn.from_str.html new file mode 100644 index 000000000..de5eb34d6 --- /dev/null +++ b/uucore/parse_time/fn.from_str.html @@ -0,0 +1,3 @@ +from_str in uucore::parse_time - Rust + +

Function uucore::parse_time::from_str[][src]

pub fn from_str(string: &str) -> Result<Duration, String>
\ No newline at end of file diff --git a/uucore/parse_time/index.html b/uucore/parse_time/index.html new file mode 100644 index 000000000..17190c30e --- /dev/null +++ b/uucore/parse_time/index.html @@ -0,0 +1,4 @@ +uucore::parse_time - Rust + +

Module uucore::parse_time[][src]

Functions

+
from_str
\ No newline at end of file diff --git a/uucore/parse_time/sidebar-items.js b/uucore/parse_time/sidebar-items.js new file mode 100644 index 000000000..e230df5cf --- /dev/null +++ b/uucore/parse_time/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["from_str",""]]}); \ No newline at end of file diff --git a/uucore/parser/parse_size/enum.ParseSizeError.html b/uucore/parser/parse_size/enum.ParseSizeError.html new file mode 100644 index 000000000..d1c47d25e --- /dev/null +++ b/uucore/parser/parse_size/enum.ParseSizeError.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/parse_size/enum.ParseSizeError.html...

+ + + \ No newline at end of file diff --git a/uucore/parser/parse_size/fn.parse_size.html b/uucore/parser/parse_size/fn.parse_size.html new file mode 100644 index 000000000..2891cf150 --- /dev/null +++ b/uucore/parser/parse_size/fn.parse_size.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/parse_size/fn.parse_size.html...

+ + + \ No newline at end of file diff --git a/uucore/parser/parse_size/index.html b/uucore/parser/parse_size/index.html new file mode 100644 index 000000000..e95a993b8 --- /dev/null +++ b/uucore/parser/parse_size/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/parse_size/index.html...

+ + + \ No newline at end of file diff --git a/uucore/parser/parse_time/fn.from_str.html b/uucore/parser/parse_time/fn.from_str.html new file mode 100644 index 000000000..7bf0fa0a2 --- /dev/null +++ b/uucore/parser/parse_time/fn.from_str.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/parse_time/fn.from_str.html...

+ + + \ No newline at end of file diff --git a/uucore/parser/parse_time/index.html b/uucore/parser/parse_time/index.html new file mode 100644 index 000000000..4e80d2b2e --- /dev/null +++ b/uucore/parser/parse_time/index.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../uucore/parse_time/index.html...

+ + + \ No newline at end of file diff --git a/uucore/perms/constant.FTS_COMFOLLOW.html b/uucore/perms/constant.FTS_COMFOLLOW.html new file mode 100644 index 000000000..0ef95b2c6 --- /dev/null +++ b/uucore/perms/constant.FTS_COMFOLLOW.html @@ -0,0 +1,3 @@ +FTS_COMFOLLOW in uucore::perms - Rust + +

Constant uucore::perms::FTS_COMFOLLOW[][src]

pub const FTS_COMFOLLOW: u8 = 1;
\ No newline at end of file diff --git a/uucore/perms/constant.FTS_LOGICAL.html b/uucore/perms/constant.FTS_LOGICAL.html new file mode 100644 index 000000000..d6cbc69fc --- /dev/null +++ b/uucore/perms/constant.FTS_LOGICAL.html @@ -0,0 +1,3 @@ +FTS_LOGICAL in uucore::perms - Rust + +

Constant uucore::perms::FTS_LOGICAL[][src]

pub const FTS_LOGICAL: u8 = 1 << 2; // 0x04u8
\ No newline at end of file diff --git a/uucore/perms/constant.FTS_PHYSICAL.html b/uucore/perms/constant.FTS_PHYSICAL.html new file mode 100644 index 000000000..ed385e3ed --- /dev/null +++ b/uucore/perms/constant.FTS_PHYSICAL.html @@ -0,0 +1,3 @@ +FTS_PHYSICAL in uucore::perms - Rust + +

Constant uucore::perms::FTS_PHYSICAL[][src]

pub const FTS_PHYSICAL: u8 = 1 << 1; // 0x02u8
\ No newline at end of file diff --git a/uucore/perms/entries/fn.get_groups.html b/uucore/perms/entries/fn.get_groups.html new file mode 100644 index 000000000..eb592d589 --- /dev/null +++ b/uucore/perms/entries/fn.get_groups.html @@ -0,0 +1,12 @@ +get_groups in uucore::perms::entries - Rust + +

Function uucore::perms::entries::get_groups[][src]

pub fn get_groups() -> IOResult<Vec<gid_t>>
Expand description

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
+

getgroups() returns the supplementary group IDs of the calling +process in list. +If size is zero, list is not modified, but the total number of +supplementary group IDs for the process is returned. This allows +the caller to determine the size of a dynamically allocated list +to be used in a further call to getgroups().

+
+
\ No newline at end of file diff --git a/uucore/perms/entries/fn.get_groups_gnu.html b/uucore/perms/entries/fn.get_groups_gnu.html new file mode 100644 index 000000000..72c50eff1 --- /dev/null +++ b/uucore/perms/entries/fn.get_groups_gnu.html @@ -0,0 +1,25 @@ +get_groups_gnu in uucore::perms::entries - Rust + +

Function uucore::perms::entries::get_groups_gnu[][src]

pub fn get_groups_gnu(arg_id: Option<u32>) -> IOResult<Vec<gid_t>>
Expand description

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+

If arg_id is None (default), get_groups_gnu moves the effective +group id (egid) to the first entry in the returned Vector. +If arg_id is Some(x), get_groups_gnu moves the id with value x +to the first entry in the returned Vector. This might be necessary +for id --groups --real if gid and egid are not equal.

+

From: https://www.man7.org/linux/man-pages/man3/getgroups.3p.html

+
+

As implied by the definition of supplementary groups, the +effective group ID may appear in the array returned by +getgroups() or it may be returned only by getegid(). Duplication +may exist, but the application needs to call getegid() to be sure +of getting all of the information. Various implementation +variations and administrative sequences cause the set of groups +appearing in the result of getgroups() to vary in order and as to +whether the effective group ID is included, even when the set of +groups is the same (in the mathematical sense of ``set’’). (The +history of a process and its parents could affect the details of +the result.)

+
+
\ No newline at end of file diff --git a/uucore/perms/entries/fn.gid2grp.html b/uucore/perms/entries/fn.gid2grp.html new file mode 100644 index 000000000..aeef04913 --- /dev/null +++ b/uucore/perms/entries/fn.gid2grp.html @@ -0,0 +1,3 @@ +gid2grp in uucore::perms::entries - Rust + +

Function uucore::perms::entries::gid2grp[][src]

pub fn gid2grp(id: gid_t) -> IOResult<String>
\ No newline at end of file diff --git a/uucore/perms/entries/fn.grp2gid.html b/uucore/perms/entries/fn.grp2gid.html new file mode 100644 index 000000000..e8be37c6d --- /dev/null +++ b/uucore/perms/entries/fn.grp2gid.html @@ -0,0 +1,3 @@ +grp2gid in uucore::perms::entries - Rust + +

Function uucore::perms::entries::grp2gid[][src]

pub fn grp2gid(name: &str) -> IOResult<gid_t>
\ No newline at end of file diff --git a/uucore/perms/entries/fn.uid2usr.html b/uucore/perms/entries/fn.uid2usr.html new file mode 100644 index 000000000..40e7a4adc --- /dev/null +++ b/uucore/perms/entries/fn.uid2usr.html @@ -0,0 +1,3 @@ +uid2usr in uucore::perms::entries - Rust + +

Function uucore::perms::entries::uid2usr[][src]

pub fn uid2usr(id: uid_t) -> IOResult<String>
\ No newline at end of file diff --git a/uucore/perms/entries/fn.usr2uid.html b/uucore/perms/entries/fn.usr2uid.html new file mode 100644 index 000000000..d8dca237d --- /dev/null +++ b/uucore/perms/entries/fn.usr2uid.html @@ -0,0 +1,3 @@ +usr2uid in uucore::perms::entries - Rust + +

Function uucore::perms::entries::usr2uid[][src]

pub fn usr2uid(name: &str) -> IOResult<uid_t>
\ No newline at end of file diff --git a/uucore/perms/entries/index.html b/uucore/perms/entries/index.html new file mode 100644 index 000000000..fded58872 --- /dev/null +++ b/uucore/perms/entries/index.html @@ -0,0 +1,34 @@ +uucore::perms::entries - Rust + +

Module uucore::perms::entries[][src]

Expand description

Get password/group file entry

+

Examples:

+
+use uucore::entries::{self, Locate};
+
+let root_group = if cfg!(any(target_os = "linux", target_os = "android")) {
+    "root"
+} else {
+    "wheel"
+};
+
+assert_eq!("root", entries::uid2usr(0).unwrap());
+assert_eq!(0, entries::usr2uid("root").unwrap());
+assert!(entries::gid2grp(0).is_ok());
+assert!(entries::grp2gid(root_group).is_ok());
+
+assert!(entries::Passwd::locate(0).is_ok());
+assert!(entries::Passwd::locate("0").is_ok());
+assert!(entries::Passwd::locate("root").is_ok());
+
+assert!(entries::Group::locate(0).is_ok());
+assert!(entries::Group::locate("0").is_ok());
+assert!(entries::Group::locate(root_group).is_ok());
+

Structs

+
Group
Passwd

Traits

+
Locate

Fetch desired entry.

+

Functions

+
get_groups

From: https://man7.org/linux/man-pages/man2/getgroups.2.html

+
get_groups_gnu

The list of group IDs returned from GNU’s groups and GNU’s id --groups +starts with the effective group ID (egid). +This is a wrapper for get_groups() to mimic this behavior.

+
gid2grp
grp2gid
uid2usr
usr2uid
\ No newline at end of file diff --git a/uucore/perms/entries/sidebar-items.js b/uucore/perms/entries/sidebar-items.js new file mode 100644 index 000000000..55270684c --- /dev/null +++ b/uucore/perms/entries/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["get_groups","From: https://man7.org/linux/man-pages/man2/getgroups.2.html"],["get_groups_gnu","The list of group IDs returned from GNU’s `groups` and GNU’s `id --groups` starts with the effective group ID (egid). This is a wrapper for `get_groups()` to mimic this behavior."],["gid2grp",""],["grp2gid",""],["uid2usr",""],["usr2uid",""]],"struct":[["Group",""],["Passwd",""]],"trait":[["Locate","Fetch desired entry."]]}); \ No newline at end of file diff --git a/uucore/perms/entries/struct.Group.html b/uucore/perms/entries/struct.Group.html new file mode 100644 index 000000000..f512b609c --- /dev/null +++ b/uucore/perms/entries/struct.Group.html @@ -0,0 +1,14 @@ +Group in uucore::perms::entries - Rust + +

Struct uucore::perms::entries::Group[][src]

pub struct Group { /* fields omitted */ }

Implementations

AKA group.gr_name

+

AKA group.gr_gid

+

Trait Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/perms/entries/struct.Passwd.html b/uucore/perms/entries/struct.Passwd.html new file mode 100644 index 000000000..7c404e554 --- /dev/null +++ b/uucore/perms/entries/struct.Passwd.html @@ -0,0 +1,39 @@ +Passwd in uucore::perms::entries - Rust + +

Struct uucore::perms::entries::Passwd[][src]

pub struct Passwd { /* fields omitted */ }

Implementations

AKA passwd.pw_name

+

AKA passwd.pw_uid

+

AKA passwd.pw_gid

+

AKA passwd.pw_gecos

+

AKA passwd.pw_shell

+

AKA passwd.pw_dir

+

AKA passwd.pw_passwd

+

This is a wrapper function for libc::getgrouplist.

+

From: https://man7.org/linux/man-pages/man3/getgrouplist.3.html

+
+

If the number of groups of which user is a member is less than or +equal to *ngroups, then the value *ngroups is returned. +If the user is a member of more than *ngroups groups, then +getgrouplist() returns -1. In this case, the value returned in +*ngroups can be used to resize the buffer passed to a further +call getgrouplist().

+
+

However, on macOS/darwin (and maybe others?) getgrouplist does +not update ngroups if ngroups is too small. Therefore, if not +updated by getgrouplist, ngroups needs to be increased in a +loop until getgrouplist stops returning -1.

+

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/perms/entries/trait.Locate.html b/uucore/perms/entries/trait.Locate.html new file mode 100644 index 000000000..ab720f0ed --- /dev/null +++ b/uucore/perms/entries/trait.Locate.html @@ -0,0 +1,6 @@ +Locate in uucore::perms::entries - Rust + +

Trait uucore::perms::entries::Locate[][src]

pub trait Locate<K> {
+    fn locate(key: K) -> IOResult<Self>
    where
        Self: Sized
; +}
Expand description

Fetch desired entry.

+

Required methods

Implementors

\ No newline at end of file diff --git a/uucore/perms/enum.IfFrom.html b/uucore/perms/enum.IfFrom.html new file mode 100644 index 000000000..c793e5f74 --- /dev/null +++ b/uucore/perms/enum.IfFrom.html @@ -0,0 +1,19 @@ +IfFrom in uucore::perms - Rust + +

Enum uucore::perms::IfFrom[][src]

pub enum IfFrom {
+    All,
+    User(u32),
+    Group(u32),
+    UserGroup(u32u32),
+}

+ Variants

+
All
User(u32)
Group(u32)
UserGroup(u32u32)

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/perms/enum.VerbosityLevel.html b/uucore/perms/enum.VerbosityLevel.html new file mode 100644 index 000000000..89b03cc8c --- /dev/null +++ b/uucore/perms/enum.VerbosityLevel.html @@ -0,0 +1,30 @@ +VerbosityLevel in uucore::perms - Rust + +

Enum uucore::perms::VerbosityLevel[][src]

pub enum VerbosityLevel {
+    Silent,
+    Changes,
+    Verbose,
+    Normal,
+}
Expand description

The various level of verbosity

+

+ Variants

+
Silent
Changes
Verbose
Normal

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/perms/fn.wrap_chown.html b/uucore/perms/fn.wrap_chown.html new file mode 100644 index 000000000..65e701e6f --- /dev/null +++ b/uucore/perms/fn.wrap_chown.html @@ -0,0 +1,6 @@ +wrap_chown in uucore::perms - Rust + +

Function uucore::perms::wrap_chown[][src]

pub fn wrap_chown<P: AsRef<Path>>(
    path: P,
    meta: &Metadata,
    dest_uid: Option<u32>,
    dest_gid: Option<u32>,
    follow: bool,
    verbosity: Verbosity
) -> Result<String, String>
Expand description

Perform the change of owner on a path +with the various options +and error messages management

+
\ No newline at end of file diff --git a/uucore/perms/index.html b/uucore/perms/index.html new file mode 100644 index 000000000..54e1a567b --- /dev/null +++ b/uucore/perms/index.html @@ -0,0 +1,13 @@ +uucore::perms - Rust + +

Module uucore::perms[][src]

Modules

+
entries

Get password/group file entry

+

Structs

+
ChownExecutor
Verbosity

Enums

+
IfFrom
VerbosityLevel

The various level of verbosity

+

Constants

+
FTS_COMFOLLOW
FTS_LOGICAL
FTS_PHYSICAL

Functions

+
wrap_chown

Perform the change of owner on a path +with the various options +and error messages management

+
\ No newline at end of file diff --git a/uucore/perms/sidebar-items.js b/uucore/perms/sidebar-items.js new file mode 100644 index 000000000..938dc1a89 --- /dev/null +++ b/uucore/perms/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["FTS_COMFOLLOW",""],["FTS_LOGICAL",""],["FTS_PHYSICAL",""]],"enum":[["IfFrom",""],["VerbosityLevel","The various level of verbosity"]],"fn":[["wrap_chown","Perform the change of owner on a path with the various options and error messages management"]],"mod":[["entries","Get password/group file entry"]],"struct":[["ChownExecutor",""],["Verbosity",""]]}); \ No newline at end of file diff --git a/uucore/perms/struct.ChownExecutor.html b/uucore/perms/struct.ChownExecutor.html new file mode 100644 index 000000000..cbbce47dd --- /dev/null +++ b/uucore/perms/struct.ChownExecutor.html @@ -0,0 +1,23 @@ +ChownExecutor in uucore::perms - Rust + +

Struct uucore::perms::ChownExecutor[][src]

pub struct ChownExecutor {
+    pub dest_uid: Option<u32>,
+    pub dest_gid: Option<u32>,
+    pub bit_flag: u8,
+    pub verbosity: Verbosity,
+    pub filter: IfFrom,
+    pub files: Vec<String>,
+    pub recursive: bool,
+    pub preserve_root: bool,
+    pub dereference: bool,
+}

+ Fields

dest_uid: Option<u32>dest_gid: Option<u32>bit_flag: u8verbosity: Verbosityfilter: IfFromfiles: Vec<String>recursive: boolpreserve_root: booldereference: bool

Implementations

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/perms/struct.Verbosity.html b/uucore/perms/struct.Verbosity.html new file mode 100644 index 000000000..240fd1849 --- /dev/null +++ b/uucore/perms/struct.Verbosity.html @@ -0,0 +1,26 @@ +Verbosity in uucore::perms - Rust + +

Struct uucore::perms::Verbosity[][src]

pub struct Verbosity {
+    pub groups_only: bool,
+    pub level: VerbosityLevel,
+}

+ Fields

groups_only: boollevel: VerbosityLevel

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/process/enum.ExitStatus.html b/uucore/process/enum.ExitStatus.html new file mode 100644 index 000000000..53b21428a --- /dev/null +++ b/uucore/process/enum.ExitStatus.html @@ -0,0 +1,29 @@ +ExitStatus in uucore::process - Rust + +

Enum uucore::process::ExitStatus[][src]

pub enum ExitStatus {
+    Code(i32),
+    Signal(i32),
+}

+ Variants

+
Code(i32)
Signal(i32)

Implementations

Trait Implementations

Returns a copy of the value. Read more

+

Performs copy-assignment from source. Read more

+

Formats the value using the given formatter. Read more

+

Formats the value using the given formatter. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The resulting type after obtaining ownership.

+

Creates owned data from borrowed data, usually by cloning. Read more

+
🔬 This is a nightly-only experimental API. (toowned_clone_into)

recently added

+

Uses borrowed data to replace owned data, usually by cloning. Read more

+

Converts the given value to a String. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/process/fn.getegid.html b/uucore/process/fn.getegid.html new file mode 100644 index 000000000..41d8a5b4c --- /dev/null +++ b/uucore/process/fn.getegid.html @@ -0,0 +1,4 @@ +getegid in uucore::process - Rust + +

Function uucore::process::getegid[][src]

pub fn getegid() -> gid_t
Expand description

getegid() returns the effective group ID of the calling process.

+
\ No newline at end of file diff --git a/uucore/process/fn.geteuid.html b/uucore/process/fn.geteuid.html new file mode 100644 index 000000000..390e2eb31 --- /dev/null +++ b/uucore/process/fn.geteuid.html @@ -0,0 +1,4 @@ +geteuid in uucore::process - Rust + +

Function uucore::process::geteuid[][src]

pub fn geteuid() -> uid_t
Expand description

geteuid() returns the effective user ID of the calling process.

+
\ No newline at end of file diff --git a/uucore/process/fn.getgid.html b/uucore/process/fn.getgid.html new file mode 100644 index 000000000..34f7c16e6 --- /dev/null +++ b/uucore/process/fn.getgid.html @@ -0,0 +1,4 @@ +getgid in uucore::process - Rust + +

Function uucore::process::getgid[][src]

pub fn getgid() -> gid_t
Expand description

getgid() returns the real group ID of the calling process.

+
\ No newline at end of file diff --git a/uucore/process/fn.getuid.html b/uucore/process/fn.getuid.html new file mode 100644 index 000000000..5ddc683cb --- /dev/null +++ b/uucore/process/fn.getuid.html @@ -0,0 +1,4 @@ +getuid in uucore::process - Rust + +

Function uucore::process::getuid[][src]

pub fn getuid() -> uid_t
Expand description

getuid() returns the real user ID of the calling process.

+
\ No newline at end of file diff --git a/uucore/process/index.html b/uucore/process/index.html new file mode 100644 index 000000000..4f42d7811 --- /dev/null +++ b/uucore/process/index.html @@ -0,0 +1,11 @@ +uucore::process - Rust + +

Module uucore::process[][src]

Enums

+
ExitStatus

Traits

+
ChildExt

Missing methods for Child objects

+

Functions

+
getegid

getegid() returns the effective group ID of the calling process.

+
geteuid

geteuid() returns the effective user ID of the calling process.

+
getgid

getgid() returns the real group ID of the calling process.

+
getuid

getuid() returns the real user ID of the calling process.

+
\ No newline at end of file diff --git a/uucore/process/sidebar-items.js b/uucore/process/sidebar-items.js new file mode 100644 index 000000000..044e1c3d8 --- /dev/null +++ b/uucore/process/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["ExitStatus",""]],"fn":[["getegid","`getegid()` returns the effective group ID of the calling process."],["geteuid","`geteuid()` returns the effective user ID of the calling process."],["getgid","`getgid()` returns the real group ID of the calling process."],["getuid","`getuid()` returns the real user ID of the calling process."]],"trait":[["ChildExt","Missing methods for Child objects"]]}); \ No newline at end of file diff --git a/uucore/process/trait.ChildExt.html b/uucore/process/trait.ChildExt.html new file mode 100644 index 000000000..21e86a5b0 --- /dev/null +++ b/uucore/process/trait.ChildExt.html @@ -0,0 +1,10 @@ +ChildExt in uucore::process - Rust + +

Trait uucore::process::ChildExt[][src]

pub trait ChildExt {
+    fn send_signal(&mut self, signal: usize) -> Result<()>;
+
fn wait_or_timeout(
        &mut self,
        timeout: Duration
    ) -> Result<Option<ExitStatus>>; +}
Expand description

Missing methods for Child objects

+

Required methods

Send a signal to a Child process.

+

Wait for a process to finish or return after the specified duration. +A timeout of zero disables the timeout.

+

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/uucore/ranges/fn.complement.html b/uucore/ranges/fn.complement.html new file mode 100644 index 000000000..953f7ebe9 --- /dev/null +++ b/uucore/ranges/fn.complement.html @@ -0,0 +1,3 @@ +complement in uucore::ranges - Rust + +

Function uucore::ranges::complement[][src]

pub fn complement(ranges: &[Range]) -> Vec<Range>
\ No newline at end of file diff --git a/uucore/ranges/fn.contain.html b/uucore/ranges/fn.contain.html new file mode 100644 index 000000000..b878ea004 --- /dev/null +++ b/uucore/ranges/fn.contain.html @@ -0,0 +1,19 @@ +contain in uucore::ranges - Rust + +

Function uucore::ranges::contain[][src]

pub fn contain(ranges: &[Range], n: usize) -> bool
Expand description

Test if at least one of the given Ranges contain the supplied value.

+

Examples:

+ +
+let ranges = uucore::ranges::Range::from_list("11,2,6-8").unwrap();
+
+assert!(!uucore::ranges::contain(&ranges, 0));
+assert!(!uucore::ranges::contain(&ranges, 1));
+assert!(!uucore::ranges::contain(&ranges, 5));
+assert!(!uucore::ranges::contain(&ranges, 10));
+
+assert!(uucore::ranges::contain(&ranges, 2));
+assert!(uucore::ranges::contain(&ranges, 6));
+assert!(uucore::ranges::contain(&ranges, 7));
+assert!(uucore::ranges::contain(&ranges, 8));
+assert!(uucore::ranges::contain(&ranges, 11));
+
\ No newline at end of file diff --git a/uucore/ranges/index.html b/uucore/ranges/index.html new file mode 100644 index 000000000..8059f4cb0 --- /dev/null +++ b/uucore/ranges/index.html @@ -0,0 +1,6 @@ +uucore::ranges - Rust + +

Module uucore::ranges[][src]

Structs

+
Range

Functions

+
complement
contain

Test if at least one of the given Ranges contain the supplied value.

+
\ No newline at end of file diff --git a/uucore/ranges/sidebar-items.js b/uucore/ranges/sidebar-items.js new file mode 100644 index 000000000..d8ce2d50e --- /dev/null +++ b/uucore/ranges/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["complement",""],["contain","Test if at least one of the given Ranges contain the supplied value."]],"struct":[["Range",""]]}); \ No newline at end of file diff --git a/uucore/ranges/struct.Range.html b/uucore/ranges/struct.Range.html new file mode 100644 index 000000000..43d342955 --- /dev/null +++ b/uucore/ranges/struct.Range.html @@ -0,0 +1,33 @@ +Range in uucore::ranges - Rust + +

Struct uucore::ranges::Range[][src]

pub struct Range {
+    pub low: usize,
+    pub high: usize,
+}

+ Fields

low: usizehigh: usize

Implementations

Trait Implementations

Formats the value using the given formatter. Read more

+

The associated error which can be returned from parsing.

+

Parses a string s to return a value of this type. Read more

+

This method returns an Ordering between self and other. Read more

+

Compares and returns the maximum of two values. Read more

+

Compares and returns the minimum of two values. Read more

+

Restrict a value to a certain interval. Read more

+

This method tests for self and other values to be equal, and is used +by ==. Read more

+

This method tests for !=.

+

This method returns an ordering between self and other values if one exists. Read more

+

This method tests less than (for self and other) and is used by the < operator. Read more

+

This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more

+

This method tests greater than (for self and other) and is used by the > operator. Read more

+

This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/ringbuffer/index.html b/uucore/ringbuffer/index.html new file mode 100644 index 000000000..26d813171 --- /dev/null +++ b/uucore/ringbuffer/index.html @@ -0,0 +1,6 @@ +uucore::ringbuffer - Rust + +

Module uucore::ringbuffer[][src]

Expand description

A fixed-size ring buffer.

+

Structs

+
RingBuffer

A fixed-size ring buffer backed by a VecDeque.

+
\ No newline at end of file diff --git a/uucore/ringbuffer/sidebar-items.js b/uucore/ringbuffer/sidebar-items.js new file mode 100644 index 000000000..313edcba4 --- /dev/null +++ b/uucore/ringbuffer/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["RingBuffer","A fixed-size ring buffer backed by a `VecDeque`."]]}); \ No newline at end of file diff --git a/uucore/ringbuffer/struct.RingBuffer.html b/uucore/ringbuffer/struct.RingBuffer.html new file mode 100644 index 000000000..5c3b7ddd0 --- /dev/null +++ b/uucore/ringbuffer/struct.RingBuffer.html @@ -0,0 +1,67 @@ +RingBuffer in uucore::ringbuffer - Rust + +

Struct uucore::ringbuffer::RingBuffer[][src]

pub struct RingBuffer<T> {
+    pub data: VecDeque<T>,
+    // some fields omitted
+}
Expand description

A fixed-size ring buffer backed by a VecDeque.

+

If the ring buffer is not full, then calling the [push_back] +method appends elements, as in a VecDeque. If the ring buffer +is full, then calling [push_back] removes the element at the +front of the buffer (in a first-in, first-out manner) before +appending the new element to the back of the buffer.

+

Use [from_iter] to take the last size elements from an +iterator.

+

Examples

+

After exceeding the size limit, the oldest elements are dropped in +favor of the newest element:

+ +
+let mut buffer: RingBuffer<u8> = RingBuffer::new(2);
+buffer.push_back(0);
+buffer.push_back(1);
+buffer.push_back(2);
+assert_eq!(vec![1, 2], buffer.data);
+

Take the last n elements from an iterator:

+ +
+let iter = [0, 1, 2].iter();
+let actual = RingBuffer::from_iter(iter, 2).data;
+let expected = VecDeque::from_iter([1, 2].iter());
+assert_eq!(expected, actual);
+

+ Fields

data: VecDeque<T>

Implementations

Append a value to the end of the ring buffer.

+

If the ring buffer is not full, this method return None. If +the ring buffer is full, appending a new element will cause the +oldest element to be evicted. In that case this method returns +that element, or None.

+

In the special case where the size limit is zero, each call to +this method with input value returns Some(value), because +the input is immediately evicted.

+

Examples

+

Appending an element when the buffer is full returns the oldest +element:

+ +
+let mut buf = RingBuffer::new(3);
+assert_eq!(None, buf.push_back(0));
+assert_eq!(None, buf.push_back(1));
+assert_eq!(None, buf.push_back(2));
+assert_eq!(Some(0), buf.push_back(3));
+

If the size limit is zero, then this method always returns the +input value:

+ +
+let mut buf = RingBuffer::new(0);
+assert_eq!(Some(0), buf.push_back(0));
+assert_eq!(Some(1), buf.push_back(1));
+assert_eq!(Some(2), buf.push_back(2));
+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/sidebar-items.js b/uucore/sidebar-items.js new file mode 100644 index 000000000..b347082c0 --- /dev/null +++ b/uucore/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"enum":[["ConversionResult",""],["InvalidEncodingHandling",""]],"externcrate":[["libc",""]],"fn":[["args",""],["args_os",""],["execution_phrase","Derive the complete execution phrase for “usage”."],["get_utility_is_second_arg",""],["set_utility_is_second_arg",""],["util_name","Derive the utility name."]],"macro":[["app",""],["crash","Display the provided error message, then `exit()` with the provided exit code"],["crash_if_err","Unwraps the Result. Instead of panicking, it exists the program with the provided exit code."],["exit","Calls `exit()` with the provided exit code."],["has",""],["msg_expects_no_more_than_one_of",""],["msg_expects_one_of",""],["msg_invalid_input",""],["msg_invalid_opt_use",""],["msg_opt_invalid_should_be",""],["msg_opt_only_usable_if",""],["return_if_err","Unwraps the Result. Instead of panicking, it shows the error and then returns from the function with the provided exit code. Assumes the current function returns an i32 value."],["safe_unwrap","Unwraps the Result. Instead of panicking, it exists the program with exit code 1."],["safe_write",""],["safe_writeln",""],["show",""],["show_error","Show an error to stderr in a similar style to GNU coreutils."],["show_error_custom_description","Show a warning to stderr in a similar style to GNU coreutils."],["show_if_err",""],["show_usage_error","Show a bad invocation help message in a similar style to GNU coreutils."],["show_warning",""],["snippet_list_join",""],["snippet_list_join_oxford_comma",""],["uio_error","Shorthand to construct [`UIoError`]-instances."]],"mod":[["backup_control",""],["coreopts",""],["encoding",""],["entries","Get password/group file entry"],["error","All utils return exit with an exit code. Usually, the following scheme is used:"],["fs",""],["fsext",""],["mode",""],["os",""],["panic",""],["parse_size",""],["parse_time",""],["perms",""],["process",""],["ranges",""],["ringbuffer","A fixed-size ring buffer."],["signals",""],["utmpx","Aims to provide platform-independent methods to obtain login records"],["version_cmp",""],["zero_copy",""]],"trait":[["Args",""]]}); \ No newline at end of file diff --git a/uucore/signals/fn.is_signal.html b/uucore/signals/fn.is_signal.html new file mode 100644 index 000000000..a952d443a --- /dev/null +++ b/uucore/signals/fn.is_signal.html @@ -0,0 +1,3 @@ +is_signal in uucore::signals - Rust + +

Function uucore::signals::is_signal[][src]

pub fn is_signal(num: usize) -> bool
\ No newline at end of file diff --git a/uucore/signals/fn.signal_by_name_or_value.html b/uucore/signals/fn.signal_by_name_or_value.html new file mode 100644 index 000000000..00784db05 --- /dev/null +++ b/uucore/signals/fn.signal_by_name_or_value.html @@ -0,0 +1,3 @@ +signal_by_name_or_value in uucore::signals - Rust + +

Function uucore::signals::signal_by_name_or_value[][src]

pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize>
\ No newline at end of file diff --git a/uucore/signals/fn.signal_name_by_value.html b/uucore/signals/fn.signal_name_by_value.html new file mode 100644 index 000000000..401af0a9c --- /dev/null +++ b/uucore/signals/fn.signal_name_by_value.html @@ -0,0 +1,3 @@ +signal_name_by_value in uucore::signals - Rust + +

Function uucore::signals::signal_name_by_value[][src]

pub fn signal_name_by_value(signal_value: usize) -> Option<&'static str>
\ No newline at end of file diff --git a/uucore/signals/index.html b/uucore/signals/index.html new file mode 100644 index 000000000..30f952278 --- /dev/null +++ b/uucore/signals/index.html @@ -0,0 +1,5 @@ +uucore::signals - Rust + +

Module uucore::signals[][src]

Statics

+
ALL_SIGNALS
DEFAULT_SIGNAL

Functions

+
is_signal
signal_by_name_or_value
signal_name_by_value
\ No newline at end of file diff --git a/uucore/signals/sidebar-items.js b/uucore/signals/sidebar-items.js new file mode 100644 index 000000000..d5db41654 --- /dev/null +++ b/uucore/signals/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["is_signal",""],["signal_by_name_or_value",""],["signal_name_by_value",""]],"static":[["ALL_SIGNALS",""],["DEFAULT_SIGNAL",""]]}); \ No newline at end of file diff --git a/uucore/signals/static.ALL_SIGNALS.html b/uucore/signals/static.ALL_SIGNALS.html new file mode 100644 index 000000000..e71cde759 --- /dev/null +++ b/uucore/signals/static.ALL_SIGNALS.html @@ -0,0 +1,3 @@ +ALL_SIGNALS in uucore::signals - Rust + +

Static uucore::signals::ALL_SIGNALS[][src]

pub static ALL_SIGNALS: [&str; 32]
\ No newline at end of file diff --git a/uucore/signals/static.DEFAULT_SIGNAL.html b/uucore/signals/static.DEFAULT_SIGNAL.html new file mode 100644 index 000000000..1c5ea2d2d --- /dev/null +++ b/uucore/signals/static.DEFAULT_SIGNAL.html @@ -0,0 +1,3 @@ +DEFAULT_SIGNAL in uucore::signals - Rust + +

Static uucore::signals::DEFAULT_SIGNAL[][src]

pub static DEFAULT_SIGNAL: usize
\ No newline at end of file diff --git a/uucore/trait.Args.html b/uucore/trait.Args.html new file mode 100644 index 000000000..d9efe3967 --- /dev/null +++ b/uucore/trait.Args.html @@ -0,0 +1,19 @@ +Args in uucore - Rust + +

Trait uucore::Args[][src]

pub trait Args: Iterator<Item = OsString> + Sized {
+    fn collect_str(self, handling: InvalidEncodingHandling) -> ConversionResult { ... }
+
fn collect_str_lossy(self) -> ConversionResult { ... } +}

Provided methods

Converts each iterator item to a String and collects these into a vector +On invalid encoding, the result will depend on the argument. This method allows to either drop entries with illegal encoding +completely (InvalidEncodingHandling::Ignore), convert them using lossy-conversion (InvalidEncodingHandling::Lossy) which will +result in strange strings or can chosen to panic (InvalidEncodingHandling::Panic).

+

Arguments

+
    +
  • handling - This switch allows to switch the behavior, when invalid encoding is encountered
  • +
+

Panics

+
    +
  • Occurs, when invalid encoding is encountered and handling is set to InvalidEncodingHandling::Panic
  • +
+

convenience function for a more slim interface

+

Implementors

\ No newline at end of file diff --git a/uucore/utmpx/constant.ACCOUNTING.html b/uucore/utmpx/constant.ACCOUNTING.html new file mode 100644 index 000000000..b5834d060 --- /dev/null +++ b/uucore/utmpx/constant.ACCOUNTING.html @@ -0,0 +1,3 @@ +ACCOUNTING in uucore::utmpx - Rust + +

Constant uucore::utmpx::ACCOUNTING[]

pub const ACCOUNTING: i16 = 9; // 9i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.BOOT_TIME.html b/uucore/utmpx/constant.BOOT_TIME.html new file mode 100644 index 000000000..31617d9ef --- /dev/null +++ b/uucore/utmpx/constant.BOOT_TIME.html @@ -0,0 +1,3 @@ +BOOT_TIME in uucore::utmpx - Rust + +

Constant uucore::utmpx::BOOT_TIME[]

pub const BOOT_TIME: i16 = 2; // 2i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.DEAD_PROCESS.html b/uucore/utmpx/constant.DEAD_PROCESS.html new file mode 100644 index 000000000..b73804e2b --- /dev/null +++ b/uucore/utmpx/constant.DEAD_PROCESS.html @@ -0,0 +1,3 @@ +DEAD_PROCESS in uucore::utmpx - Rust + +

Constant uucore::utmpx::DEAD_PROCESS[]

pub const DEAD_PROCESS: i16 = 8; // 8i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.EMPTY.html b/uucore/utmpx/constant.EMPTY.html new file mode 100644 index 000000000..1b94db725 --- /dev/null +++ b/uucore/utmpx/constant.EMPTY.html @@ -0,0 +1,3 @@ +EMPTY in uucore::utmpx - Rust + +

Constant uucore::utmpx::EMPTY[]

pub const EMPTY: i16 = 0; // 0i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.INIT_PROCESS.html b/uucore/utmpx/constant.INIT_PROCESS.html new file mode 100644 index 000000000..ab010e503 --- /dev/null +++ b/uucore/utmpx/constant.INIT_PROCESS.html @@ -0,0 +1,3 @@ +INIT_PROCESS in uucore::utmpx - Rust + +

Constant uucore::utmpx::INIT_PROCESS[]

pub const INIT_PROCESS: i16 = 5; // 5i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.LOGIN_PROCESS.html b/uucore/utmpx/constant.LOGIN_PROCESS.html new file mode 100644 index 000000000..2ef41d48f --- /dev/null +++ b/uucore/utmpx/constant.LOGIN_PROCESS.html @@ -0,0 +1,3 @@ +LOGIN_PROCESS in uucore::utmpx - Rust + +

Constant uucore::utmpx::LOGIN_PROCESS[]

pub const LOGIN_PROCESS: i16 = 6; // 6i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.NEW_TIME.html b/uucore/utmpx/constant.NEW_TIME.html new file mode 100644 index 000000000..dd35f0c3e --- /dev/null +++ b/uucore/utmpx/constant.NEW_TIME.html @@ -0,0 +1,3 @@ +NEW_TIME in uucore::utmpx - Rust + +

Constant uucore::utmpx::NEW_TIME[]

pub const NEW_TIME: i16 = 3; // 3i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.OLD_TIME.html b/uucore/utmpx/constant.OLD_TIME.html new file mode 100644 index 000000000..bd5a145e8 --- /dev/null +++ b/uucore/utmpx/constant.OLD_TIME.html @@ -0,0 +1,3 @@ +OLD_TIME in uucore::utmpx - Rust + +

Constant uucore::utmpx::OLD_TIME[]

pub const OLD_TIME: i16 = 4; // 4i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.RUN_LVL.html b/uucore/utmpx/constant.RUN_LVL.html new file mode 100644 index 000000000..34b150c54 --- /dev/null +++ b/uucore/utmpx/constant.RUN_LVL.html @@ -0,0 +1,3 @@ +RUN_LVL in uucore::utmpx - Rust + +

Constant uucore::utmpx::RUN_LVL[]

pub const RUN_LVL: i16 = 1; // 1i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.USER_PROCESS.html b/uucore/utmpx/constant.USER_PROCESS.html new file mode 100644 index 000000000..672bf05b1 --- /dev/null +++ b/uucore/utmpx/constant.USER_PROCESS.html @@ -0,0 +1,3 @@ +USER_PROCESS in uucore::utmpx - Rust + +

Constant uucore::utmpx::USER_PROCESS[]

pub const USER_PROCESS: i16 = 7; // 7i16
\ No newline at end of file diff --git a/uucore/utmpx/constant.UT_HOSTSIZE.html b/uucore/utmpx/constant.UT_HOSTSIZE.html new file mode 100644 index 000000000..0d702fc5d --- /dev/null +++ b/uucore/utmpx/constant.UT_HOSTSIZE.html @@ -0,0 +1,3 @@ +UT_HOSTSIZE in uucore::utmpx - Rust + +

Constant uucore::utmpx::UT_HOSTSIZE[]

pub const UT_HOSTSIZE: usize = 256; // 0x0000_0000_0000_0100usize
\ No newline at end of file diff --git a/uucore/utmpx/constant.UT_IDSIZE.html b/uucore/utmpx/constant.UT_IDSIZE.html new file mode 100644 index 000000000..ab2d62075 --- /dev/null +++ b/uucore/utmpx/constant.UT_IDSIZE.html @@ -0,0 +1,3 @@ +UT_IDSIZE in uucore::utmpx - Rust + +

Constant uucore::utmpx::UT_IDSIZE[][src]

pub const UT_IDSIZE: usize = 4;
\ No newline at end of file diff --git a/uucore/utmpx/constant.UT_LINESIZE.html b/uucore/utmpx/constant.UT_LINESIZE.html new file mode 100644 index 000000000..e8b028ffd --- /dev/null +++ b/uucore/utmpx/constant.UT_LINESIZE.html @@ -0,0 +1,3 @@ +UT_LINESIZE in uucore::utmpx - Rust + +

Constant uucore::utmpx::UT_LINESIZE[]

pub const UT_LINESIZE: usize = 32; // 0x0000_0000_0000_0020usize
\ No newline at end of file diff --git a/uucore/utmpx/constant.UT_NAMESIZE.html b/uucore/utmpx/constant.UT_NAMESIZE.html new file mode 100644 index 000000000..0e0e99f32 --- /dev/null +++ b/uucore/utmpx/constant.UT_NAMESIZE.html @@ -0,0 +1,3 @@ +UT_NAMESIZE in uucore::utmpx - Rust + +

Constant uucore::utmpx::UT_NAMESIZE[]

pub const UT_NAMESIZE: usize = 32; // 0x0000_0000_0000_0020usize
\ No newline at end of file diff --git a/uucore/utmpx/fn.endutxent.html b/uucore/utmpx/fn.endutxent.html new file mode 100644 index 000000000..a60d7e0eb --- /dev/null +++ b/uucore/utmpx/fn.endutxent.html @@ -0,0 +1,3 @@ +endutxent in uucore::utmpx - Rust + +

Function uucore::utmpx::endutxent[]

pub unsafe extern "C" fn endutxent()
\ No newline at end of file diff --git a/uucore/utmpx/fn.getutxent.html b/uucore/utmpx/fn.getutxent.html new file mode 100644 index 000000000..985be411f --- /dev/null +++ b/uucore/utmpx/fn.getutxent.html @@ -0,0 +1,3 @@ +getutxent in uucore::utmpx - Rust + +

Function uucore::utmpx::getutxent[]

pub unsafe extern "C" fn getutxent() -> *mut utmpx
\ No newline at end of file diff --git a/uucore/utmpx/fn.setutxent.html b/uucore/utmpx/fn.setutxent.html new file mode 100644 index 000000000..2cbe2820a --- /dev/null +++ b/uucore/utmpx/fn.setutxent.html @@ -0,0 +1,3 @@ +setutxent in uucore::utmpx - Rust + +

Function uucore::utmpx::setutxent[]

pub unsafe extern "C" fn setutxent()
\ No newline at end of file diff --git a/uucore/utmpx/fn.utmpxname.html b/uucore/utmpx/fn.utmpxname.html new file mode 100644 index 000000000..57d287efa --- /dev/null +++ b/uucore/utmpx/fn.utmpxname.html @@ -0,0 +1,3 @@ +utmpxname in uucore::utmpx - Rust + +

Function uucore::utmpx::utmpxname[]

pub unsafe extern "C" fn utmpxname(file: *const i8) -> i32
\ No newline at end of file diff --git a/uucore/utmpx/index.html b/uucore/utmpx/index.html new file mode 100644 index 000000000..a9800766c --- /dev/null +++ b/uucore/utmpx/index.html @@ -0,0 +1,28 @@ +uucore::utmpx - Rust + +

Module uucore::utmpx[][src]

Expand description

Aims to provide platform-independent methods to obtain login records

+

ONLY support linux, macos and freebsd for the time being

+

Examples:

+
+use uucore::utmpx::Utmpx;
+for ut in Utmpx::iter_all_records() {
+    if ut.is_user_process() {
+        println!("{}: {}", ut.host(), ut.user())
+    }
+}
+

Specifying the path to login record:

+ +
+use uucore::utmpx::Utmpx;
+for ut in Utmpx::iter_all_records().read_from("/some/where/else") {
+    if ut.is_user_process() {
+        println!("{}: {}", ut.host(), ut.user())
+    }
+}
+

Re-exports

+
pub extern crate time;
pub use crate::*;

Structs

+
Utmpx
UtmpxIter

Iterator of login records

+

Constants

+
ACCOUNTING
BOOT_TIME
DEAD_PROCESS
EMPTY
INIT_PROCESS
LOGIN_PROCESS
NEW_TIME
OLD_TIME
RUN_LVL
USER_PROCESS
UT_HOSTSIZE
UT_IDSIZE
UT_LINESIZE
UT_NAMESIZE

Statics

+
DEFAULT_FILE

Functions

+
endutxent
getutxent
setutxent
utmpxname
\ No newline at end of file diff --git a/uucore/utmpx/sidebar-items.js b/uucore/utmpx/sidebar-items.js new file mode 100644 index 000000000..9764e07e3 --- /dev/null +++ b/uucore/utmpx/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"constant":[["ACCOUNTING",""],["BOOT_TIME",""],["DEAD_PROCESS",""],["EMPTY",""],["INIT_PROCESS",""],["LOGIN_PROCESS",""],["NEW_TIME",""],["OLD_TIME",""],["RUN_LVL",""],["USER_PROCESS",""],["UT_HOSTSIZE",""],["UT_IDSIZE",""],["UT_LINESIZE",""],["UT_NAMESIZE",""]],"externcrate":[["time",""]],"fn":[["endutxent",""],["getutxent",""],["setutxent",""],["utmpxname",""]],"static":[["DEFAULT_FILE",""]],"struct":[["Utmpx",""],["UtmpxIter","Iterator of login records"]]}); \ No newline at end of file diff --git a/uucore/utmpx/static.DEFAULT_FILE.html b/uucore/utmpx/static.DEFAULT_FILE.html new file mode 100644 index 000000000..c139460b0 --- /dev/null +++ b/uucore/utmpx/static.DEFAULT_FILE.html @@ -0,0 +1,3 @@ +DEFAULT_FILE in uucore::utmpx - Rust + +

Static uucore::utmpx::DEFAULT_FILE[][src]

pub static DEFAULT_FILE: &str
\ No newline at end of file diff --git a/uucore/utmpx/struct.Utmpx.html b/uucore/utmpx/struct.Utmpx.html new file mode 100644 index 000000000..f069ee3dc --- /dev/null +++ b/uucore/utmpx/struct.Utmpx.html @@ -0,0 +1,23 @@ +Utmpx in uucore::utmpx - Rust + +

Struct uucore::utmpx::Utmpx[][src]

pub struct Utmpx { /* fields omitted */ }

Implementations

A.K.A. ut.ut_type

+

A.K.A. ut.ut_pid

+

A.K.A. ut.ut_id

+

A.K.A. ut.ut_user

+

A.K.A. ut.ut_host

+

A.K.A. ut.ut_line

+

A.K.A. ut.ut_tv

+

A.K.A. ut.ut_exit

+

Return (e_termination, e_exit)

+

Consumes the Utmpx, returning the underlying C struct utmpx

+

Canonicalize host name using DNS

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/utmpx/struct.UtmpxIter.html b/uucore/utmpx/struct.UtmpxIter.html new file mode 100644 index 000000000..1daf60291 --- /dev/null +++ b/uucore/utmpx/struct.UtmpxIter.html @@ -0,0 +1,135 @@ +UtmpxIter in uucore::utmpx - Rust + +

Struct uucore::utmpx::UtmpxIter[][src]

pub struct UtmpxIter;
Expand description

Iterator of login records

+

Implementations

Sets the name of the utmpx-format file for the other utmpx functions to access.

+

If not set, default record file will be used(file path depends on the target OS)

+

Trait Implementations

The type of the elements being iterated over.

+

Advances the iterator and returns the next value. Read more

+

Returns the bounds on the remaining length of the iterator. Read more

+

Consumes the iterator, counting the number of iterations and returning it. Read more

+

Consumes the iterator, returning the last element. Read more

+
🔬 This is a nightly-only experimental API. (iter_advance_by)

recently added

+

Advances the iterator by n elements. Read more

+

Returns the nth element of the iterator. Read more

+

Creates an iterator starting at the same point, but stepping by +the given amount at each iteration. Read more

+

Takes two iterators and creates a new iterator over both in sequence. Read more

+

‘Zips up’ two iterators into a single iterator of pairs. Read more

+
🔬 This is a nightly-only experimental API. (iter_intersperse)

recently added

+

Creates a new iterator which places a copy of separator between adjacent +items of the original iterator. Read more

+
🔬 This is a nightly-only experimental API. (iter_intersperse)

recently added

+

Creates a new iterator which places an item generated by separator +between adjacent items of the original iterator. Read more

+

Takes a closure and creates an iterator which calls that closure on each +element. Read more

+

Calls a closure on each element of an iterator. Read more

+

Creates an iterator which uses a closure to determine if an element +should be yielded. Read more

+

Creates an iterator that both filters and maps. Read more

+

Creates an iterator which gives the current iteration count as well as +the next value. Read more

+

Creates an iterator which can use the peek and peek_mut methods +to look at the next element of the iterator without consuming it. See +their documentation for more information. Read more

+

Creates an iterator that skips elements based on a predicate. Read more

+

Creates an iterator that yields elements based on a predicate. Read more

+
🔬 This is a nightly-only experimental API. (iter_map_while)

recently added

+

Creates an iterator that both yields elements based on a predicate and maps. Read more

+

Creates an iterator that skips the first n elements. Read more

+

Creates an iterator that yields the first n elements, or fewer +if the underlying iterator ends sooner. Read more

+

An iterator adaptor similar to fold that holds internal state and +produces a new iterator. Read more

+

Creates an iterator that works like map, but flattens nested structure. Read more

+

Creates an iterator that flattens nested structure. Read more

+

Creates an iterator which ends after the first None. Read more

+

Does something with each element of an iterator, passing the value on. Read more

+

Borrows an iterator, rather than consuming it. Read more

+

Transforms an iterator into a collection. Read more

+

Consumes an iterator, creating two collections from it. Read more

+
🔬 This is a nightly-only experimental API. (iter_partition_in_place)

new API

+

Reorders the elements of this iterator in-place according to the given predicate, +such that all those that return true precede all those that return false. +Returns the number of true elements found. Read more

+
🔬 This is a nightly-only experimental API. (iter_is_partitioned)

new API

+

Checks if the elements of this iterator are partitioned according to the given predicate, +such that all those that return true precede all those that return false. Read more

+

An iterator method that applies a function as long as it returns +successfully, producing a single, final value. Read more

+

An iterator method that applies a fallible function to each item in the +iterator, stopping at the first error and returning that error. Read more

+

Folds every element into an accumulator by applying an operation, +returning the final result. Read more

+

Reduces the elements to a single one, by repeatedly applying a reducing +operation. Read more

+

Tests if every element of the iterator matches a predicate. Read more

+

Tests if any element of the iterator matches a predicate. Read more

+

Searches for an element of an iterator that satisfies a predicate. Read more

+

Applies function to the elements of iterator and returns +the first non-none result. Read more

+
🔬 This is a nightly-only experimental API. (try_find)

new API

+

Applies function to the elements of iterator and returns +the first true result or the first error. Read more

+

Searches for an element in an iterator, returning its index. Read more

+

Searches for an element in an iterator from the right, returning its +index. Read more

+

Returns the maximum element of an iterator. Read more

+

Returns the minimum element of an iterator. Read more

+

Returns the element that gives the maximum value from the +specified function. Read more

+

Returns the element that gives the maximum value with respect to the +specified comparison function. Read more

+

Returns the element that gives the minimum value from the +specified function. Read more

+

Returns the element that gives the minimum value with respect to the +specified comparison function. Read more

+

Reverses an iterator’s direction. Read more

+

Converts an iterator of pairs into a pair of containers. Read more

+

Creates an iterator which copies all of its elements. Read more

+

Creates an iterator which clones all of its elements. Read more

+

Repeats an iterator endlessly. Read more

+

Sums the elements of an iterator. Read more

+

Iterates over the entire iterator, multiplying all the elements Read more

+

Lexicographically compares the elements of this Iterator with those +of another. Read more

+
🔬 This is a nightly-only experimental API. (iter_order_by)

Lexicographically compares the elements of this Iterator with those +of another with respect to the specified comparison function. Read more

+

Lexicographically compares the elements of this Iterator with those +of another. Read more

+
🔬 This is a nightly-only experimental API. (iter_order_by)

Lexicographically compares the elements of this Iterator with those +of another with respect to the specified comparison function. Read more

+

Determines if the elements of this Iterator are equal to those of +another. Read more

+
🔬 This is a nightly-only experimental API. (iter_order_by)

Determines if the elements of this Iterator are equal to those of +another with respect to the specified equality function. Read more

+

Determines if the elements of this Iterator are unequal to those of +another. Read more

+

Determines if the elements of this Iterator are lexicographically +less than those of another. Read more

+

Determines if the elements of this Iterator are lexicographically +less or equal to those of another. Read more

+

Determines if the elements of this Iterator are lexicographically +greater than those of another. Read more

+

Determines if the elements of this Iterator are lexicographically +greater than or equal to those of another. Read more

+
🔬 This is a nightly-only experimental API. (is_sorted)

new API

+

Checks if the elements of this iterator are sorted. Read more

+
🔬 This is a nightly-only experimental API. (is_sorted)

new API

+

Checks if the elements of this iterator are sorted using the given comparator function. Read more

+
🔬 This is a nightly-only experimental API. (is_sorted)

new API

+

Checks if the elements of this iterator are sorted using the given key extraction +function. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type of the elements being iterated over.

+

Which kind of iterator are we turning this into?

+

Creates an iterator from a value. Read more

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/version_cmp/fn.version_cmp.html b/uucore/version_cmp/fn.version_cmp.html new file mode 100644 index 000000000..b79706c33 --- /dev/null +++ b/uucore/version_cmp/fn.version_cmp.html @@ -0,0 +1,3 @@ +version_cmp in uucore::version_cmp - Rust + +

Function uucore::version_cmp::version_cmp[][src]

pub fn version_cmp(a: &str, b: &str) -> Ordering
\ No newline at end of file diff --git a/uucore/version_cmp/index.html b/uucore/version_cmp/index.html new file mode 100644 index 000000000..6705b256e --- /dev/null +++ b/uucore/version_cmp/index.html @@ -0,0 +1,4 @@ +uucore::version_cmp - Rust + +

Module uucore::version_cmp[][src]

Functions

+
version_cmp
\ No newline at end of file diff --git a/uucore/version_cmp/sidebar-items.js b/uucore/version_cmp/sidebar-items.js new file mode 100644 index 000000000..ed948c6d2 --- /dev/null +++ b/uucore/version_cmp/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["version_cmp",""]]}); \ No newline at end of file diff --git a/uucore/zero_copy/index.html b/uucore/zero_copy/index.html new file mode 100644 index 000000000..2c1bf4e99 --- /dev/null +++ b/uucore/zero_copy/index.html @@ -0,0 +1,5 @@ +uucore::zero_copy - Rust + +

Module uucore::zero_copy[][src]

Structs

+
ZeroCopyWriter

Traits

+
AsRawObject
FromRawObject
\ No newline at end of file diff --git a/uucore/zero_copy/sidebar-items.js b/uucore/zero_copy/sidebar-items.js new file mode 100644 index 000000000..f72325af3 --- /dev/null +++ b/uucore/zero_copy/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"struct":[["ZeroCopyWriter",""]],"trait":[["AsRawObject",""],["FromRawObject",""]]}); \ No newline at end of file diff --git a/uucore/zero_copy/struct.ZeroCopyWriter.html b/uucore/zero_copy/struct.ZeroCopyWriter.html new file mode 100644 index 000000000..1c0353abb --- /dev/null +++ b/uucore/zero_copy/struct.ZeroCopyWriter.html @@ -0,0 +1,23 @@ +ZeroCopyWriter in uucore::zero_copy - Rust + +

Struct uucore::zero_copy::ZeroCopyWriter[][src]

pub struct ZeroCopyWriter<T: Write + AsRawObject + Sized> { /* fields omitted */ }

Implementations

Trait Implementations

Write a buffer into this writer, returning how many bytes were written. Read more

+

Flush this output stream, ensuring that all intermediately buffered +contents reach their destination. Read more

+

Like write, except that it writes from a slice of buffers. Read more

+
🔬 This is a nightly-only experimental API. (can_vector)

Determines if this Writer has an efficient write_vectored +implementation. Read more

+

Attempts to write an entire buffer into this writer. Read more

+
🔬 This is a nightly-only experimental API. (write_all_vectored)

Attempts to write multiple buffers into this writer. Read more

+

Writes a formatted string into this writer, returning any error +encountered. Read more

+

Creates a “by reference” adaptor for this instance of Write. Read more

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

+

Immutably borrows from an owned value. Read more

+

Mutably borrows from an owned value. Read more

+

Performs the conversion.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+

The type returned in the event of a conversion error.

+

Performs the conversion.

+
\ No newline at end of file diff --git a/uucore/zero_copy/trait.AsRawObject.html b/uucore/zero_copy/trait.AsRawObject.html new file mode 100644 index 000000000..3a8f64baa --- /dev/null +++ b/uucore/zero_copy/trait.AsRawObject.html @@ -0,0 +1,5 @@ +AsRawObject in uucore::zero_copy - Rust + +

Trait uucore::zero_copy::AsRawObject[][src]

pub trait AsRawObject {
+    fn as_raw_object(&self) -> RawFd;
+}

Required methods

Implementors

\ No newline at end of file diff --git a/uucore/zero_copy/trait.FromRawObject.html b/uucore/zero_copy/trait.FromRawObject.html new file mode 100644 index 000000000..8324b5d40 --- /dev/null +++ b/uucore/zero_copy/trait.FromRawObject.html @@ -0,0 +1,7 @@ +FromRawObject in uucore::zero_copy - Rust + +

Trait uucore::zero_copy::FromRawObject[][src]

pub trait FromRawObject: Sized {
+    unsafe fn from_raw_object(obj: RawFd) -> Option<Self>;
+}

Required methods

Safety

+

ToDO …

+

Implementors

\ No newline at end of file diff --git a/uucore_procs/all.html b/uucore_procs/all.html new file mode 100644 index 000000000..04ac79750 --- /dev/null +++ b/uucore_procs/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Macros

Attribute Macros

\ No newline at end of file diff --git a/uucore_procs/attr.gen_uumain.html b/uucore_procs/attr.gen_uumain.html new file mode 100644 index 000000000..2c2823e6a --- /dev/null +++ b/uucore_procs/attr.gen_uumain.html @@ -0,0 +1,3 @@ +gen_uumain in uucore_procs - Rust + +

Attribute Macro uucore_procs::gen_uumain[][src]

#[gen_uumain]
\ No newline at end of file diff --git a/uucore_procs/index.html b/uucore_procs/index.html new file mode 100644 index 000000000..273db8e00 --- /dev/null +++ b/uucore_procs/index.html @@ -0,0 +1,5 @@ +uucore_procs - Rust + +

Crate uucore_procs[][src]

Macros

+
main

Attribute Macros

+
gen_uumain
\ No newline at end of file diff --git a/uucore_procs/macro.main!.html b/uucore_procs/macro.main!.html new file mode 100644 index 000000000..30e847171 --- /dev/null +++ b/uucore_procs/macro.main!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.main.html...

+ + + \ No newline at end of file diff --git a/uucore_procs/macro.main.html b/uucore_procs/macro.main.html new file mode 100644 index 000000000..290126868 --- /dev/null +++ b/uucore_procs/macro.main.html @@ -0,0 +1,3 @@ +main in uucore_procs - Rust + +

Macro uucore_procs::main[][src]

main!() { /* proc-macro */ }
\ No newline at end of file diff --git a/uucore_procs/sidebar-items.js b/uucore_procs/sidebar-items.js new file mode 100644 index 000000000..8c94db323 --- /dev/null +++ b/uucore_procs/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"attr":[["gen_uumain",""]],"macro":[["main",""]]}); \ No newline at end of file diff --git a/wc/all.html b/wc/all.html new file mode 100644 index 000000000..b3920d537 --- /dev/null +++ b/wc/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/wc/fn.main.html b/wc/fn.main.html new file mode 100644 index 000000000..ece1c982a --- /dev/null +++ b/wc/fn.main.html @@ -0,0 +1,3 @@ +main in wc - Rust + +

Function wc::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/wc/index.html b/wc/index.html new file mode 100644 index 000000000..88200c429 --- /dev/null +++ b/wc/index.html @@ -0,0 +1,4 @@ +wc - Rust + +

Crate wc[][src]

Functions

+
main
\ No newline at end of file diff --git a/wc/sidebar-items.js b/wc/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/wc/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/wheel.svg b/wheel.svg new file mode 100644 index 000000000..01da3b24c --- /dev/null +++ b/wheel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/who/all.html b/who/all.html new file mode 100644 index 000000000..3b91b764c --- /dev/null +++ b/who/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/who/fn.main.html b/who/fn.main.html new file mode 100644 index 000000000..25aaf1073 --- /dev/null +++ b/who/fn.main.html @@ -0,0 +1,3 @@ +main in who - Rust + +

Function who::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/who/index.html b/who/index.html new file mode 100644 index 000000000..0ffb7a607 --- /dev/null +++ b/who/index.html @@ -0,0 +1,4 @@ +who - Rust + +

Crate who[][src]

Functions

+
main
\ No newline at end of file diff --git a/who/sidebar-items.js b/who/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/who/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/whoami/all.html b/whoami/all.html new file mode 100644 index 000000000..e964ac18c --- /dev/null +++ b/whoami/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/whoami/fn.main.html b/whoami/fn.main.html new file mode 100644 index 000000000..e0d201598 --- /dev/null +++ b/whoami/fn.main.html @@ -0,0 +1,3 @@ +main in whoami - Rust + +

Function whoami::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/whoami/index.html b/whoami/index.html new file mode 100644 index 000000000..56be845aa --- /dev/null +++ b/whoami/index.html @@ -0,0 +1,4 @@ +whoami - Rust + +

Crate whoami[][src]

Functions

+
main
\ No newline at end of file diff --git a/whoami/sidebar-items.js b/whoami/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/whoami/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file diff --git a/yes/all.html b/yes/all.html new file mode 100644 index 000000000..58c54bce7 --- /dev/null +++ b/yes/all.html @@ -0,0 +1,5 @@ +List of all items in this crate + +

List of all items[] + +

Functions

\ No newline at end of file diff --git a/yes/fn.main.html b/yes/fn.main.html new file mode 100644 index 000000000..806527281 --- /dev/null +++ b/yes/fn.main.html @@ -0,0 +1,3 @@ +main in yes - Rust + +

Function yes::main[][src]

pub(crate) fn main()
\ No newline at end of file diff --git a/yes/index.html b/yes/index.html new file mode 100644 index 000000000..6648739fe --- /dev/null +++ b/yes/index.html @@ -0,0 +1,4 @@ +yes - Rust + +

Crate yes[][src]

Functions

+
main
\ No newline at end of file diff --git a/yes/sidebar-items.js b/yes/sidebar-items.js new file mode 100644 index 000000000..a5d4937c7 --- /dev/null +++ b/yes/sidebar-items.js @@ -0,0 +1 @@ +initSidebarItems({"fn":[["main",""]]}); \ No newline at end of file