apt-get source
and get the version that is used on your system by default, or pull the latest version out of the repositories. We will choose the second option: it is more convenient and familiar.
git clone git://git.sv.gnu.org/coreutils
git clone git://git.savannah.gnu.org/gnulib.git
coreutils/src/yes.c
, and open it.
int main (int argc, char **argv) { foo(); ... }
if (x < foo (y, z)) haha = bar[4] + 5; else { while (z) { haha += foo (z, z); z--; } return ++x + bar (); }
yes.c
begins with a comment required for all GPL programs. He had already managed to kill my eyes in other programs and the need for its presence was a mystery to me. It turns out that the text of this comment is fixed in the instructions for using the GPL. It is written in it that everyone who wants to release their software under the GPL must add these 12 lines of copyright statement to the beginning of each source code file.
initialize_main
. This function is intended for the program to perform its specific actions on the arguments. In practice, in Coreutils, there is not a single utility that would use this function for something useful. Everywhere the stub is used, represented in the coreutils/src/system.h
:
#ifndef initialize_main # define initialize_main(ac, av) #endif
user@laptop:~$ yes --version yes (GNU coreutils) 8.5 Usage: yes [STRING]... or: yes OPTION
user@laptop:~$ /usr/bin/yes --version yes (GNU coreutils) 8.5 user@laptop:~$ cp /usr/bin/yes ./foo user@laptop:~$ ./foo --version yes (GNU coreutils) 8.5
PROGRAM_NAME
specifically defined at the beginning of the file:
/* The official name of this program (eg, no `g' prefix). */ #define PROGRAM_NAME "yes"
argv[0]
and is used when displaying errors and prompts:
user@laptop:~$ yes --help Usage: yes [STRING]... or: yes OPTION user@laptop:~$ /usr/bin/yes --help Usage: /usr/bin/yes [STRING]... or: /usr/bin/yes OPTION
argv[0]
is placed in the global variable program_name
by calling the set_program_name
function in the second line of main
:
set_program_name (argv[0]);
set_program_name
function set_program_name
provided by the Gnulib library. The corresponding code is located in the gnulib/lib/
directory, in the progname.h
and progname.c
. It is interesting to note that set_program_name
not only saves the values argv[0]
into the global variable program_name
declared in progname.h
, but also performs additional conversions related to the subtleties of using GNU Libtool , a tool for developing dynamic libraries.
_
, the use of which can be found in the usage
function:
void usage (int status) { if (status != EXIT_SUCCESS) fprintf (stderr, _("Try `%s --help' for more information.\n"), program_name); ... }
_
is in the system.h
file already familiar to us:
#define _(msgid) gettext (msgid)
main
:
setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE);
main
code, we meet the following line:
atexit (close_stdout);
close_stdout
function, which eliminates data loss if we replace stdout
with some file descriptor and use buffered output. But I did not succeed in finding the source code for this function and understanding what is actually happening there, whether any additional actions for cleaning up resources are being performed.
getopt
or getopt_long
in a loop. More information about getopt can be read on the Internet, and on Habré, they also wrote about it.
parse_long_options
for handling the --version
and --help
arguments, which any GNU application must support. It is located in the gnulib/lib/long-options.c
file and uses getopt_long
in its work.
parse_long_options
. Then it is checked that no more options-keys are passed and the remaining arguments, if any, are just arbitrary strings:
parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version, usage, AUTHORS, (char const *) NULL); if (getopt_long (argc, argv, "+", NULL, NULL) != -1) usage (EXIT_FAILURE);
if (argc <= optind) { optind = argc; argv[argc++] = bad_cast ("y"); }
argv[argc]
not an error: the ANSI C standard requires that the argv[argc]
element be a null pointer.
while (true) { int i; for (i = optind; i < argc; i++) if (fputs (argv[i], stdout) == EOF || putchar (i == argc - 1 ? '\n' : ' ') == EOF) error (EXIT_FAILURE, errno, _("standard output")); }
if
condition, and not in its body. So, Kernigan and Ritchie did not lie when they wrote that an experienced C-programmer implements the copying of lines like this:
while (*dst++ = *src++) ;
Source: https://habr.com/ru/post/133408/