VirtualBox

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

Last change on this file since 106579 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • 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 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - cat like utility.
4 */
5
6/*
7 * Copyright (C) 2017-2024 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