VirtualBox

source: vbox/trunk/src/VBox/Runtime/tools/RTCat.cpp@ 105959

Last change on this file since 105959 was 99775, checked in by vboxsync, 19 months ago

*: Mark functions as static if not used outside of a given compilation unit. Enables the compiler to optimize inlining, reduces the symbol tables, exposes unused functions and in some rare cases exposes mismtaches between function declarations and definitions, but most importantly reduces the number of parfait reports for the extern-function-no-forward-declaration category. This should not result in any functional changes, bugref:3409

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.9 KB
Line 
1/* $Id: RTCat.cpp 99775 2023-05-12 12:21:58Z vboxsync $ */
2/** @file
3 * IPRT - cat like utility.
4 */
5
6/*
7 * Copyright (C) 2017-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <iprt/vfs.h>
42
43#include <iprt/buildconfig.h>
44#include <iprt/errcore.h>
45#include <iprt/file.h>
46#include <iprt/getopt.h>
47#include <iprt/initterm.h>
48#include <iprt/message.h>
49#include <iprt/param.h>
50#include <iprt/path.h>
51#include <iprt/stream.h>
52#include <iprt/string.h>
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58/**
59 * CAT command options.
60 */
61typedef struct RTCMDCATOPTS
62{
63 bool fShowEnds; /**< -E */
64 bool fShowNonPrinting; /**< -v */
65 bool fShowTabs; /**< -T */
66 bool fSqueezeBlankLines; /**< -s */
67 bool fNumberLines; /**< -n */
68 bool fNumberNonBlankLines; /**< -b */
69 bool fAdvisoryOutputLock; /**< -l */
70 bool fUnbufferedOutput; /**< -u */
71} RTCMDCATOPTS;
72/** Pointer to const CAT options. */
73typedef RTCMDCATOPTS const *PCRTCMDCATOPTS;
74
75
76
77/**
78 * Outputs the source raw.
79 *
80 * @returns Command exit, error messages written using RTMsg*.
81 * @param hVfsOutput The output I/O stream.
82 * @param hVfsSrc The input I/O stream.
83 * @param pszSrc The input name.
84 */
85static RTEXITCODE rtCmdCatShowRaw(RTVFSIOSTREAM hVfsOutput, RTVFSIOSTREAM hVfsSrc, const char *pszSrc)
86{
87 int rc = RTVfsUtilPumpIoStreams(hVfsSrc, hVfsOutput, 0 /*cbBufHint*/);
88 if (RT_SUCCESS(rc))
89 return RTEXITCODE_SUCCESS;
90 return RTMsgErrorExitFailure("Error catting '%s': %Rrc", pszSrc, rc);
91}
92
93
94/**
95 * Outputs the source with complicated formatting.
96 *
97 * @returns Command exit, error messages written using RTMsg*.
98 * @param hVfsOutput The output I/O stream.
99 * @param hVfsSrc The input I/O stream.
100 * @param pszSrc The input name.
101 */
102static RTEXITCODE rtCmdCatShowComplicated(RTVFSIOSTREAM hVfsOutput, RTVFSIOSTREAM hVfsSrc, const char *pszSrc,
103 PCRTCMDCATOPTS pOpts)
104{
105 if (pOpts->fShowEnds)
106 RTMsgWarning("--show-ends is not implemented\n");
107 if (pOpts->fShowTabs)
108 RTMsgWarning("--show-tabs is not implemented\n");
109 if (pOpts->fShowNonPrinting)
110 RTMsgWarning("--show-nonprinting is not implemented\n");
111 if (pOpts->fSqueezeBlankLines)
112 RTMsgWarning("--squeeze-blank is not implemented\n");
113 if (pOpts->fNumberLines)
114 RTMsgWarning("--number is not implemented\n");
115 if (pOpts->fNumberNonBlankLines)
116 RTMsgWarning("--number-nonblank is not implemented\n");
117 return rtCmdCatShowRaw(hVfsOutput, hVfsSrc, pszSrc);
118}
119
120
121/**
122 * Opens the input file.
123 *
124 * @returns Command exit, error messages written using RTMsg*.
125 *
126 * @param pszFile The input filename.
127 * @param phVfsIos Where to return the input stream handle.
128 */
129static RTEXITCODE rtCmdCatOpenInput(const char *pszFile, PRTVFSIOSTREAM phVfsIos)
130{
131 int rc;
132
133 if (!strcmp(pszFile, "-"))
134 {
135 rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_INPUT,
136 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
137 true /*fLeaveOpen*/,
138 phVfsIos);
139 if (RT_FAILURE(rc))
140 return RTMsgErrorExitFailure("Error opening standard input: %Rrc", rc);
141 }
142 else
143 {
144 uint32_t offError = 0;
145 RTERRINFOSTATIC ErrInfo;
146 rc = RTVfsChainOpenIoStream(pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
147 phVfsIos, &offError, RTErrInfoInitStatic(&ErrInfo));
148 if (RT_FAILURE(rc))
149 return RTVfsChainMsgErrorExitFailure("RTVfsChainOpenIoStream", pszFile, rc, offError, &ErrInfo.Core);
150 }
151
152 return RTEXITCODE_SUCCESS;
153
154}
155
156
157/**
158 * A /bin/cat clone.
159 *
160 * @returns Program exit code.
161 *
162 * @param cArgs The number of arguments.
163 * @param papszArgs The argument vector. (Note that this may be
164 * reordered, so the memory must be writable.)
165 */
166static RTEXITCODE RTCmdCat(unsigned cArgs, char **papszArgs)
167{
168
169 /*
170 * Parse the command line.
171 */
172 static const RTGETOPTDEF s_aOptions[] =
173 {
174 { "--show-all", 'A', RTGETOPT_REQ_NOTHING },
175 { "--number-nonblanks", 'b', RTGETOPT_REQ_NOTHING },
176 { "--show-ends-and-nonprinting", 'e', RTGETOPT_REQ_NOTHING },
177 { "--show-ends", 'E', RTGETOPT_REQ_NOTHING },
178 { "--advisory-output-lock", 'l', RTGETOPT_REQ_NOTHING },
179 { "--number", 'n', RTGETOPT_REQ_NOTHING },
180 { "--squeeze-blank", 's', RTGETOPT_REQ_NOTHING },
181 { "--show-tabs-and-nonprinting", 't', RTGETOPT_REQ_NOTHING },
182 { "--show-tabs", 'T', RTGETOPT_REQ_NOTHING },
183 { "--unbuffered-output", 'u', RTGETOPT_REQ_NOTHING },
184 { "--show-nonprinting", 'v', RTGETOPT_REQ_NOTHING },
185 };
186
187 RTCMDCATOPTS Opts;
188 Opts.fShowEnds = false;
189 Opts.fShowNonPrinting = false;
190 Opts.fShowTabs = false;
191 Opts.fSqueezeBlankLines = false;
192 Opts.fNumberLines = false;
193 Opts.fNumberNonBlankLines = false;
194 Opts.fAdvisoryOutputLock = false;
195 Opts.fUnbufferedOutput = false;
196
197 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
198 unsigned cProcessed = 0;
199 RTVFSIOSTREAM hVfsOutput = NIL_RTVFSIOSTREAM;
200 int rc = RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
201 true /*fLeaveOpen*/, &hVfsOutput);
202 if (RT_FAILURE(rc))
203 return RTMsgErrorExitFailure("RTVfsIoStrmFromStdHandle: %Rrc", rc);
204
205 RTGETOPTSTATE GetState;
206 rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
207 RTGETOPTINIT_FLAGS_OPTS_FIRST);
208 if (RT_SUCCESS(rc))
209 {
210 bool fContinue = true;
211 do
212 {
213 RTGETOPTUNION ValueUnion;
214 int chOpt = RTGetOpt(&GetState, &ValueUnion);
215 switch (chOpt)
216 {
217 case 0:
218 /*
219 * If we've processed any files we're done. Otherwise take
220 * input from stdin and write the output to stdout.
221 */
222 if (cProcessed > 0)
223 {
224 fContinue = false;
225 break;
226 }
227 ValueUnion.psz = "-";
228 RT_FALL_THRU();
229 case VINF_GETOPT_NOT_OPTION:
230 {
231 RTVFSIOSTREAM hVfsSrc;
232 RTEXITCODE rcExit2 = rtCmdCatOpenInput(ValueUnion.psz, &hVfsSrc);
233 if (rcExit2 == RTEXITCODE_SUCCESS)
234 {
235 if ( Opts.fShowEnds
236 || Opts.fShowTabs
237 || Opts.fShowNonPrinting
238 || Opts.fSqueezeBlankLines
239 || Opts.fNumberLines
240 || Opts.fNumberNonBlankLines)
241 rcExit2 = rtCmdCatShowComplicated(hVfsOutput, hVfsSrc, ValueUnion.psz, &Opts);
242 else
243 rcExit2 = rtCmdCatShowRaw(hVfsOutput, hVfsSrc, ValueUnion.psz);
244 RTVfsIoStrmRelease(hVfsSrc);
245 }
246 if (rcExit2 != RTEXITCODE_SUCCESS)
247 rcExit = rcExit2;
248 cProcessed++;
249 break;
250 }
251
252 case 'A':
253 Opts.fShowNonPrinting = true;
254 Opts.fShowEnds = true;
255 Opts.fShowTabs = true;
256 break;
257
258 case 'b':
259 Opts.fNumberNonBlankLines = true;
260 break;
261
262 case 'e':
263 Opts.fShowNonPrinting = true;
264 RT_FALL_THRU();
265 case 'E':
266 Opts.fShowEnds = true;
267 break;
268
269 case 'l':
270 Opts.fAdvisoryOutputLock = true;
271 break;
272
273 case 'n':
274 Opts.fNumberLines = true;
275 Opts.fNumberNonBlankLines = false;
276 break;
277
278 case 's':
279 Opts.fSqueezeBlankLines = true;
280 break;
281
282 case 't':
283 Opts.fShowNonPrinting = true;
284 RT_FALL_THRU();
285 case 'T':
286 Opts.fShowTabs = true;
287 break;
288
289 case 'u': /* currently ignored */
290 Opts.fUnbufferedOutput = true;
291 break;
292
293 case 'v':
294 Opts.fShowNonPrinting = true;
295 break;
296
297 case 'h':
298 RTPrintf("Usage: to be written\nOption dump:\n");
299 for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
300 RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
301 fContinue = false;
302 break;
303
304 case 'V':
305 RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
306 fContinue = false;
307 break;
308
309 default:
310 rcExit = RTGetOptPrintError(chOpt, &ValueUnion);
311 fContinue = false;
312 break;
313 }
314 } while (fContinue);
315 }
316 else
317 rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "RTGetOptInit: %Rrc", rc);
318 RTVfsIoStrmRelease(hVfsOutput);
319 return rcExit;
320}
321
322
323int main(int argc, char **argv)
324{
325 int rc = RTR3InitExe(argc, &argv, 0);
326 if (RT_FAILURE(rc))
327 return RTMsgInitFailure(rc);
328 return RTCmdCat(argc, argv);
329}
330
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette