1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS conCATenation tool
4  * FILE:            cmdutils/cat/cat.c
5  * PURPOSE:         Concatenates STDIN or an arbitrary number of files to STDOUT
6  * PROGRAMMERS:     David Welch
7  *                  Semyon Novikov (tappak)
8  *                  Herm�s B�lusca - Ma�to
9  */
10 
11 #include <stdio.h>
12 
13 #ifdef _WIN32
14 #include <string.h>         // Required for _stricmp()
15 #include <fcntl.h>          // Required for _setmode flags
16 #include <io.h>             // Required for _setmode()
17 #else
18 #include <strings.h>        // Required for strcasecmp()
19 #define O_TEXT   0x4000
20 #define O_BINARY 0x8000
21 #define _setmode(fd, mode)  // This function is useless in *nix world
22 #define _stricmp strcasecmp
23 #endif
24 
25 #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0]))
26 
27 void help(void)
28 {
29     fprintf(stdout,
30             "\n"
31             "ReactOS File Concatenation Tool\n"
32             "\n"
33             "Usage: cat [options] [file [...]]\n"
34             "options - Currently ignored\n");
35 }
36 
37 int main(int argc, char* argv[])
38 {
39     int i;
40     FILE* in;
41     unsigned char buff[512];
42     size_t cnt, readcnt;
43 
44     if (argc >= 2)
45     {
46         if (_stricmp(argv[1], "-h"    ) == 0 ||
47             _stricmp(argv[1], "--help") == 0 ||
48             _stricmp(argv[1], "/?"    ) == 0 ||
49             _stricmp(argv[1], "/help" ) == 0)
50         {
51             help();
52             return 0;
53         }
54     }
55 
56     /* Set STDOUT to binary */
57     _setmode(_fileno(stdout), O_BINARY);
58 
59     /* Special case where we run 'cat' without any argument: we use STDIN */
60     if (argc <= 1)
61     {
62         unsigned int ch;
63 
64         /* Set STDIN to binary */
65         _setmode(_fileno(stdin), O_BINARY);
66 
67 #if 0 // Version using feof()
68         ch = fgetc(stdin);
69         while (!feof(stdin))
70         {
71             putchar(ch);
72             ch = fgetc(stdin);
73         }
74 #else
75         while ((ch = fgetc(stdin)) != EOF)
76         {
77             putchar(ch);
78         }
79 #endif
80 
81         return 0;
82     }
83 
84     /* We have files: read them and output them to STDOUT */
85     for (i = 1; i < argc; i++)
86     {
87         /* Open the file in binary read mode */
88         in = fopen(argv[i], "rb");
89         if (in == NULL)
90         {
91             fprintf(stderr, "Failed to open file '%s'\n", argv[i]);
92             return -1;
93         }
94 
95         /* Dump the file to STDOUT */
96         cnt = 0; readcnt = 0;
97         while (readcnt == cnt)
98         {
99             /* Read data from the input file */
100             cnt = ARRAYSIZE(buff);
101             readcnt = fread(&buff, sizeof(buff[0]), cnt, in);
102             if (readcnt != cnt)
103             {
104                 /*
105                  * The real number of read bytes differs from the number of bytes
106                  * we wanted to read, so either a reading error occurred, or EOF
107                  * was reached while reading. Bail out if it is a reading error.
108                  */
109                 if (!feof(in))
110                 {
111                     fprintf(stderr, "Error while reading file '%s'\n", argv[i]);
112                     fclose(in);
113                     return -1;
114                 }
115             }
116 
117             /* Nothing to be read anymore, so we can gracefully break */
118             if (readcnt == 0) break;
119 
120             /* Write data to STDOUT */
121             fwrite(&buff, sizeof(buff[0]), readcnt, stdout);
122         }
123 
124         /* Finally close the file */
125         fclose(in);
126     }
127 
128     return 0;
129 }
130 
131 /* EOF */
132