-
Notifications
You must be signed in to change notification settings - Fork 0
/
xcode_redirect.hpp
99 lines (92 loc) · 3.8 KB
/
xcode_redirect.hpp
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
//39E995D00DDE0519FDF5506EED902869AEC1C39E
// xcode_redirect.hpp
//
// Created by Marcus Darden on 1/13/19.
// Copyright © 2019 Marcus Darden. All rights reserved.
//
// Usage: add the following line to main().
// xcode_redirect(argc, argv);
#ifndef xcode_redirect_hpp
#define xcode_redirect_hpp
#include <iostream>
#include <cstdio>
#include <cstring>
inline char *get_filename_and_move_count(int &optind, char *argv[], int &move_count);
inline void rotate_argv(int move_count, char *argv[], int &optind, int &argc);
// REQUIRES: argc & argv from main(), and optind from getopt.h (optional)
// MODIFIES: optind is incremented until it equals argc
// argc is decremented to discount any redirected members of argv
// EFFECTS:
// Looks for extra arguments after getopt() finishes reading options.
// It replaces simple shell functionality by using freopen() to change
// stdin (from < infilename or <infilename),
// stdout (from > outfilename or >outfilename), and/or
// stderr (from 2> errfilename or 2>errfilename).
inline void xcode_redirect(int &argc, char *argv[], int optind = 1) {
char *infile = nullptr, *outfile = nullptr, *errfile = nullptr;
int move_count = 0;
while (optind < argc) {
switch (*argv[optind]) {
case '<': // redirect input formatted as '< file' or '<file'
infile = get_filename_and_move_count(optind, argv, move_count);
if (!freopen(infile, "r", stdin)) {
std::cerr << "Unable to open input file: " << infile << std::endl;
exit(1);
} // if
break;
case '>': // redirect output formatted as '> file' or '>file'
outfile = get_filename_and_move_count(optind, argv, move_count);
if (!freopen(outfile, "w", stdout)) {
std::cerr << "Unable to open output file: " << outfile << std::endl;
exit(1);
} // if
break;
case '2': // redirect error formatted as '2> file' or '2>file'
if (*(argv[optind] + 1) == '>') {
errfile = get_filename_and_move_count(optind, argv, move_count);
if (!freopen(errfile, "w", stderr)) {
std::cerr << "Unable to open error file: " << errfile << std::endl;
exit(1);
} // if
} // if
break;
default: // not a redirection parameter
move_count = 0;
} // switch
++optind;
if (move_count > 0) {
rotate_argv(move_count, argv, optind, argc);
}
} // while
} // xcode_redirect()
inline void rotate_argv(int move_count, char *argv[], int &optind, int &argc) {
int moveind = optind - move_count;
char *temp_pre1 = argv[moveind];
char *temp_pre2 = argv[moveind + 1];
while (moveind + move_count < argc) {
argv[moveind] = argv[moveind + move_count];
++moveind;
} // while
argv[moveind++] = temp_pre1;
if (move_count == 2) {
argv[moveind] = temp_pre2;
} // if
optind -= move_count;
argc -= move_count;
} // rotate_argv()
inline char *get_filename_and_move_count(int &optind, char *argv[], int &move_count) {
if (strlen(argv[optind]) > 2) {
move_count = 1;
// Must offset by 1 character (the <), offset by more if they put space(s) before filename
int offset = 1;
// Must also offset more for 2> (redirecting error output)
if (argv[optind][0] == '2')
++offset;
while (argv[optind][offset] == ' ')
++offset;
return argv[optind] + offset;
} // if
move_count = 2;
return argv[++optind];
} // get_filename_and_move_count()
#endif /* xcode_redirect_hpp */