finally release cat knowledgepage
This commit is contained in:
parent
7c4d991c5f
commit
85145ba1e2
@ -71,6 +71,7 @@ I'm vaccinated against COVID-19. Are you?
|
|||||||
<A HREF="#privacy">#privacy</A>,
|
<A HREF="#privacy">#privacy</A>,
|
||||||
<A HREF="/thegame">/thegame</A>;
|
<A HREF="/thegame">/thegame</A>;
|
||||||
<B>knowledge</B>:
|
<B>knowledge</B>:
|
||||||
|
<A HREF="/knowledge/cat/">cat(1)</A>;
|
||||||
<A HREF="/knowledge/netbsd/">NetBSD</A>;
|
<A HREF="/knowledge/netbsd/">NetBSD</A>;
|
||||||
<A HREF="/knowledge/true">true(1)</A>;
|
<A HREF="/knowledge/true">true(1)</A>;
|
||||||
<B>shilling</B>:
|
<B>shilling</B>:
|
||||||
|
106
homepage/knowledge/cat/cat.c
Normal file
106
homepage/knowledge/cat/cat.c
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define STDIN_NAME "<stdin>"
|
||||||
|
#define STDOUT_NAME "<stdout>"
|
||||||
|
|
||||||
|
/* these are the predicted errors that could occur */
|
||||||
|
enum error_type{
|
||||||
|
FILE_ACCESS,
|
||||||
|
FILE_CLOSE,
|
||||||
|
FILE_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
/* this is an error function that will print to standard error the error that
|
||||||
|
* occurred in the program and exit */
|
||||||
|
void
|
||||||
|
error(enum error_type type, char *argv0, char *file_name){
|
||||||
|
switch(type){
|
||||||
|
case FILE_ACCESS:
|
||||||
|
fprintf(stderr, "%s: %s: cannot open file\n", argv0, file_name);
|
||||||
|
break;
|
||||||
|
case FILE_CLOSE:
|
||||||
|
fprintf(stderr, "%s: %s: cannot close file\n", argv0, file_name);
|
||||||
|
break;
|
||||||
|
case FILE_WRITE:
|
||||||
|
fprintf(stderr, "%s: %s: cannot write to file\n", argv0, file_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print input to output, returns 0 if successful and 1 if unsuccessful */
|
||||||
|
int
|
||||||
|
file_copy(FILE *input, FILE *output){
|
||||||
|
char c;
|
||||||
|
while((c = getc(input)) != EOF)
|
||||||
|
if(putc(c, output) == EOF)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[]){
|
||||||
|
/* the name of the file being printed (for diagnostics) */
|
||||||
|
char *file_name;
|
||||||
|
|
||||||
|
/* allocate this ahead of time */
|
||||||
|
char *stdin_file_name = STDIN_NAME;
|
||||||
|
|
||||||
|
/* the file pointer of the file being printed */
|
||||||
|
FILE *input;
|
||||||
|
|
||||||
|
/* this will always be stdout */
|
||||||
|
FILE *output = stdout;
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* whether or not options are being parsed */
|
||||||
|
int parsing_opts = 1;
|
||||||
|
|
||||||
|
/* usage with 0 arguments - print standard input to standard output */
|
||||||
|
if(argc == 1 && file_copy(stdin, stdout))
|
||||||
|
error(FILE_WRITE, argv[0], STDOUT_NAME);
|
||||||
|
else if(argc == 1)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for(i = 1; i < argc; ++i){
|
||||||
|
/* parsing options */
|
||||||
|
|
||||||
|
/* after `--`, interpret `--`, `-`, and `-u` as literal
|
||||||
|
* filenames */
|
||||||
|
if(parsing_opts && !strcmp(argv[i], "--")){
|
||||||
|
parsing_opts = 0;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ignore `-u` if still parsing options */
|
||||||
|
}else if(parsing_opts && !strcmp(argv[i], "-u"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* take `-` to mean standard input if still parsing options */
|
||||||
|
else if(parsing_opts && !strcmp(argv[i], "-")){
|
||||||
|
file_name = stdin_file_name;
|
||||||
|
input = stdin;
|
||||||
|
|
||||||
|
/* non-option; open the file and make sure file_name points to
|
||||||
|
* the right string */
|
||||||
|
}else{
|
||||||
|
file_name = argv[i];
|
||||||
|
input = fopen(file_name, "r");
|
||||||
|
if(input == NULL)
|
||||||
|
error(FILE_ACCESS, argv[0], file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* print input to output */
|
||||||
|
if(file_copy(input, output))
|
||||||
|
error(FILE_WRITE, argv[0], STDOUT_NAME);
|
||||||
|
|
||||||
|
/* close input file if it's not stdin */
|
||||||
|
if(input != stdin && fclose(input))
|
||||||
|
error(FILE_CLOSE, argv[0], file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* exit successfully */
|
||||||
|
return 0;
|
||||||
|
}
|
@ -60,8 +60,8 @@ window.load_highlighting = function(language){
|
|||||||
}
|
}
|
||||||
</SCRIPT>
|
</SCRIPT>
|
||||||
|
|
||||||
<H1>POSIX cat(1) WIP ARTICLE</H1>
|
<H1>POSIX cat(1)</H1>
|
||||||
<H3>updated 2021-06-21</H3>
|
<H3>updated 2021-08-06</H3>
|
||||||
<HR ALIGN="left" SIZE="1" WIDTH="25%" />
|
<HR ALIGN="left" SIZE="1" WIDTH="25%" />
|
||||||
<P><CODE>cat</CODE> on a POSIX or otherwise UNIX-like system is a program that exists to concatenate files; to “join” one file at its end to another at its start, and output that resulting file to standard output.</P>
|
<P><CODE>cat</CODE> on a POSIX or otherwise UNIX-like system is a program that exists to concatenate files; to “join” one file at its end to another at its start, and output that resulting file to standard output.</P>
|
||||||
<P><CODE>cat</CODE> was introduced in UNIX v1 to supercede the program pr which printed the contents of a single file to the screen (McIlroy); its first-edition manual page described cat as “about the easiest way to print a file” (“cat(1)”). <CODE>cat</CODE>’s modern, typical use is more or less the same; it’s often introduced to UNIX beginners as a method to print the contents of a file to the screen, which is why many implementations of <CODE>cat</CODE> include options that are technically redundant - see the often-included <CODE>cat</CODE> <CODE>-e</CODE>, <CODE>-t</CODE>, and <CODE>-v</CODE> that replace the ends of lines, tabs, and invisible characters respectively with printing portrayals (“cat(1p)”).</P>
|
<P><CODE>cat</CODE> was introduced in UNIX v1 to supercede the program pr which printed the contents of a single file to the screen (McIlroy); its first-edition manual page described cat as “about the easiest way to print a file” (“cat(1)”). <CODE>cat</CODE>’s modern, typical use is more or less the same; it’s often introduced to UNIX beginners as a method to print the contents of a file to the screen, which is why many implementations of <CODE>cat</CODE> include options that are technically redundant - see the often-included <CODE>cat</CODE> <CODE>-e</CODE>, <CODE>-t</CODE>, and <CODE>-v</CODE> that replace the ends of lines, tabs, and invisible characters respectively with printing portrayals (“cat(1p)”).</P>
|
||||||
@ -73,20 +73,31 @@ window.load_highlighting = function(language){
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define STDIN_NAME "<stdin>"
|
#define STDIN_NAME "<stdin>"
|
||||||
#define STDOUT_NAME "<stdout>"
|
#define STDOUT_NAME "<stdout>"
|
||||||
|
|
||||||
/* these two errors will exit out of the program with an unsuccessful status,
|
/* these are the predicted errors that could occur */
|
||||||
* and print a diagnostic message to standard error */
|
enum error_type{
|
||||||
void
|
FILE_ACCESS,
|
||||||
file_access_error(char *argv0, char *file_name){
|
FILE_CLOSE,
|
||||||
fprintf(stderr, "%s: %s: cannot open file\n", argv0, file_name);
|
FILE_WRITE
|
||||||
exit(1);
|
};
|
||||||
}
|
|
||||||
|
|
||||||
|
/* this is an error function that will print to standard error the error that
|
||||||
|
* occurred in the program and exit */
|
||||||
void
|
void
|
||||||
file_write_error(char *argv0, char *file_name){
|
error(enum error_type type, char *argv0, char *file_name){
|
||||||
fprintf(stderr, "%s: %s: error writing to file\n", argv0, file_name);
|
switch(type){
|
||||||
|
case FILE_ACCESS:
|
||||||
|
fprintf(stderr, "%s: %s: cannot open file\n", argv0, file_name);
|
||||||
|
break;
|
||||||
|
case FILE_CLOSE:
|
||||||
|
fprintf(stderr, "%s: %s: cannot close file\n", argv0, file_name);
|
||||||
|
break;
|
||||||
|
case FILE_WRITE:
|
||||||
|
fprintf(stderr, "%s: %s: cannot write to file\n", argv0, file_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +132,7 @@ main(int argc, char *argv[]){
|
|||||||
|
|
||||||
/* usage with 0 arguments - print standard input to standard output */
|
/* usage with 0 arguments - print standard input to standard output */
|
||||||
if(argc == 1 && file_copy(stdin, stdout))
|
if(argc == 1 && file_copy(stdin, stdout))
|
||||||
file_write_error(argv[0], STDOUT_NAME);
|
error(FILE_WRITE, argv[0], STDOUT_NAME);
|
||||||
else if(argc == 1)
|
else if(argc == 1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@ -130,16 +141,16 @@ main(int argc, char *argv[]){
|
|||||||
|
|
||||||
/* after `--`, interpret `--`, `-`, and `-u` as literal
|
/* after `--`, interpret `--`, `-`, and `-u` as literal
|
||||||
* filenames */
|
* filenames */
|
||||||
if(parsing_opts && !strcmp(argv[i], "--")){
|
if(parsing_opts && !strcmp(argv[i], "--")){
|
||||||
parsing_opts = 0;
|
parsing_opts = 0;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* ignore `-u` if still parsing options */
|
/* ignore `-u` if still parsing options */
|
||||||
}else if(parsing_opts && !strcmp(argv[i], "-u"))
|
}else if(parsing_opts && !strcmp(argv[i], "-u"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* take `-` to mean standard input if still parsing options */
|
/* take `-` to mean standard input if still parsing options */
|
||||||
else if(parsing_opts && !strcmp(argv[i], "-")){
|
else if(parsing_opts && !strcmp(argv[i], "-")){
|
||||||
file_name = stdin_file_name;
|
file_name = stdin_file_name;
|
||||||
input = stdin;
|
input = stdin;
|
||||||
|
|
||||||
@ -147,14 +158,18 @@ main(int argc, char *argv[]){
|
|||||||
* the right string */
|
* the right string */
|
||||||
}else{
|
}else{
|
||||||
file_name = argv[i];
|
file_name = argv[i];
|
||||||
input = fopen(file_name, "r");
|
input = fopen(file_name, "r");
|
||||||
if(input == NULL)
|
if(input == NULL)
|
||||||
file_access_error(argv[0], file_name);
|
error(FILE_ACCESS, argv[0], file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* print input to output */
|
/* print input to output */
|
||||||
if(file_copy(input, output))
|
if(file_copy(input, output))
|
||||||
file_write_error(argv[0], STDOUT_NAME);
|
error(FILE_WRITE, argv[0], STDOUT_NAME);
|
||||||
|
|
||||||
|
/* close input file if it's not stdin */
|
||||||
|
if(input != stdin && fclose(input))
|
||||||
|
error(FILE_CLOSE, argv[0], file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exit successfully */
|
/* exit successfully */
|
||||||
@ -162,6 +177,9 @@ main(int argc, char *argv[]){
|
|||||||
}
|
}
|
||||||
</CODE></PRE>
|
</CODE></PRE>
|
||||||
|
|
||||||
|
<P>
|
||||||
|
This is also available at <A HREF="/knowledge/cat/cat.c">/knowledge/cat/cat.c on this website</A> as a plain .c file with which you can toy.
|
||||||
|
</P>
|
||||||
<P>It’s worth noting that this concept of cat as a utility that sequentially prints given files to standard output means <CODE>cat</CODE> can be replaced by a simple shell script that does the same using <CODE>dd</CODE> and <CODE>printf</CODE>; <CODE>cat</CODE> as defined by POSIX is actually totally redundant to other POSIX utilities. Here’s the shell script:</P>
|
<P>It’s worth noting that this concept of cat as a utility that sequentially prints given files to standard output means <CODE>cat</CODE> can be replaced by a simple shell script that does the same using <CODE>dd</CODE> and <CODE>printf</CODE>; <CODE>cat</CODE> as defined by POSIX is actually totally redundant to other POSIX utilities. Here’s the shell script:</P>
|
||||||
<INPUT ID="shell_toggle" ONCLICK="window.load_highlighting('shell');" TYPE="button" VALUE="Press this button to enable syntax highlighting within this code." />
|
<INPUT ID="shell_toggle" ONCLICK="window.load_highlighting('shell');" TYPE="button" VALUE="Press this button to enable syntax highlighting within this code." />
|
||||||
<PRE><CODE CLASS="language-shell" DATA-LANG="shell">
|
<PRE><CODE CLASS="language-shell" DATA-LANG="shell">
|
||||||
@ -208,9 +226,16 @@ done
|
|||||||
exit 0
|
exit 0
|
||||||
</CODE></PRE>
|
</CODE></PRE>
|
||||||
|
|
||||||
<P>It's worth noting that the <CODE>dd_</CODE> shell function in the above sample that allows for re-aliasing of <CODE>dd</CODE> to <CODE>dd bs=1</CODE> could be replaced with a shell variable <CODE>$DD</CODE> with the initial value <CODE>dd</CODE> and a changed value according to <CODE>-u</CODE> of <CODE>dd bs=1</CODE>. However, <CODE>alias dd="dd bs=1"</CODE> would not work due to how shell aliases are parsed (ShellCheck).</P>
|
<P>
|
||||||
|
It's worth noting that the <CODE>dd_</CODE> shell function in the above sample that allows for re-aliasing of <CODE>dd</CODE> to <CODE>dd bs=1</CODE> could be replaced with a shell variable <CODE>$DD</CODE> with the initial value <CODE>dd</CODE> and a changed value according to <CODE>-u</CODE> of <CODE>dd bs=1</CODE>.
|
||||||
|
However, <CODE>alias dd="dd bs=1"</CODE> would not work due to how shell aliases are parsed (ShellCheck).
|
||||||
|
</P>
|
||||||
|
|
||||||
<P><CODE>cat</CODE> doesn't work well as a shell script though. The script is relatively slow for short files and very slow for very large files (though <CODE>dd</CODE> itself should probably be used to copy large files from one medium to another anyway). This is provided for educational purposes (though I personally use this shell script in my system PATH; the C implementation provided compiles to a much larger binary using gcc 11.1.0, so this saves a couple kilobytes).</P>
|
<P>
|
||||||
|
<CODE>cat</CODE> doesn't work well as a shell script though.
|
||||||
|
The script is relatively slow for short files and very slow for very large files (though <CODE>dd</CODE> itself should probably be used to copy large files from one medium to another anyway).
|
||||||
|
This is provided for educational purposes.
|
||||||
|
</P>
|
||||||
|
|
||||||
<H2>Cited media and further reading</H2><UL>
|
<H2>Cited media and further reading</H2><UL>
|
||||||
<LI>Articles<UL>
|
<LI>Articles<UL>
|
||||||
|
Loading…
Reference in New Issue
Block a user