Skip to content
Permalink
Browse files

Switch b_head() from optget() to getopt_long()

  • Loading branch information...
krader1961 committed Sep 16, 2019
1 parent 57085ad commit c58464184a1c292d2eedb435fc1d69c06a0edf3f
Showing with 145 additions and 59 deletions.
  1. +8 −0 config_ast.h.in
  2. +83 −32 src/cmd/ksh93/cmds/head.c
  3. +2 −0 src/cmd/ksh93/docs/conf.py
  4. +0 −27 src/cmd/ksh93/docs/head.1
  5. +51 −0 src/cmd/ksh93/docs/head.rst
  6. +1 −0 src/cmd/ksh93/docs/index.rst
@@ -23,6 +23,7 @@
#define _CONFIG_AST_H 1

#include <inttypes.h>
#include <limits.h>
#include <stdbool.h>
#include <sys/types.h>

@@ -176,6 +177,13 @@
#mesondefine _ast_intmax_long
#define _ast_fltmax_t long double

// BSD systems provide this symbol but GNU/Linux does not. We could do this as
// a config time feature test that maps to a #mesondefine but that doesn't
// seem necessary; at least given where it is used in this code.
#ifndef OFF_MAX
#define OFF_MAX LONG_MAX
#endif

#mesondefine _has_sighandler_t
#if !_has_sighandler_t
typedef void (*sighandler_t)(int);
@@ -27,68 +27,119 @@
#include "config_ast.h" // IWYU pragma: keep

#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>

#include "ast.h"
#include "builtins.h"
#include "defs.h"
#include "error.h"
#include "option.h"
#include "sfio.h"
#include "shcmd.h"
#include "stdlib.h"

static const char *short_options = "+:n:c:qs:v";
static const struct option long_options[] = {
{"help", no_argument, NULL, 1}, // all builtins support --help
{"lines", required_argument, NULL, 'n'},
{"bytes", required_argument, NULL, 'c'},
{"skip", required_argument, NULL, 's'},
{"quiet", no_argument, NULL, 'q'},
{"silent", no_argument, NULL, 'q'},
{"verbose", no_argument, NULL, 'v'},
{NULL, 0, NULL, 0}};

//
// Builtin `head` command.
//
int b_head(int argc, char **argv, Shbltin_t *context) {
static const char header_fmt[] = "\n==> %s <==\n";

Sfio_t *fp;
int opt;
char *cp;
off_t keep = 10;
off_t skip = 0;
int delim = '\n';
off_t moved;
int delim = '\n';
int header = 1;
char *format = (char *)header_fmt + 1;
int n;
Shell_t *shp = context->shp;
char *cmd = argv[0];

if (cmdinit(argc, argv, context, 0)) return -1;
while ((n = optget(argv, sh_opthead))) {
switch (n) { //!OCLINT(MissingDefaultStatement)
case 'c':
delim = -1;
/*FALLTHROUGH*/
case 'n':
if (opt_info.offset && argv[opt_info.index][opt_info.offset] == 'c') {
delim = -1;
opt_info.offset++;

optind = 0;
while ((opt = getopt_long(argc, argv, short_options, long_options, NULL)) != -1) {
switch (opt) {
case 1: {
builtin_print_help(shp, cmd);
return 0;
}
case 'c': {
char *cp;
int64_t n = strton64(optarg, &cp, NULL, 0);
if (*cp || n < 0 || n > OFF_MAX) {
errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -c", optarg);
return 2;
}
keep = opt_info.number;
if (keep <= 0) {
error(2, "%s: %I*d: positive numeric option argument expected", opt_info.name,
sizeof(keep), keep);
keep = n;
delim = -1;
break;
}
case 'n': {
char *cp;
int64_t n = strton64(optarg, &cp, NULL, 0);
if (*cp || n < 0 || n > OFF_MAX) {
errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -n", optarg);
return 2;
}
keep = n;
delim = '\n';
break;
case 'q':
}
case 'q': {
header = argc;
break;
case 'v':
}
case 'v': {
header = 0;
break;
case 's':
skip = opt_info.number;
break;
case ':':
error(2, "%s", opt_info.arg);
}
case 's': {
char *cp;
int64_t n = strton64(optarg, &cp, NULL, 0);
if (*cp || n < 0 || n > OFF_MAX) {
errormsg(SH_DICT, ERROR_exit(0), "%s: invalid value for -s", optarg);
return 2;
}
skip = n;
break;
case '?':
error(ERROR_usage(2), "%s", opt_info.arg);
__builtin_unreachable();
}
case ':': {
builtin_missing_argument(shp, cmd, argv[opterr]);
return 2;
}
case '?': {
char *cp;
int64_t n = strton64(argv[opterr] + 1, &cp, NULL, 0);
if (!*cp && n >= 0 && n <= OFF_MAX) {
keep = n;
delim = '\n';
break;
}
builtin_unknown_option(shp, cmd, argv[opterr]);
return 2;
}
default: { abort(); }
}
}
argv += opt_info.index;
argc -= opt_info.index;
if (error_info.errors) {
error(ERROR_usage(2), "%s", optusage(NULL));
__builtin_unreachable();
}
argv += optind;
argc -= optind;

cp = *argv;
if (cp) argv++;
do {
@@ -103,4 +103,6 @@
'David J. Korn, et. al.', '1'),
('dirname', 'dirname', 'return directory portion of file name',
'David J. Korn, et. al.', '1'),
('head', 'head', 'output beginning portion of one or more files',
'David J. Korn, et. al.', '1'),
]

This file was deleted.

@@ -0,0 +1,51 @@
.. default-role:: code

:index:`head` -- output beginning portion of one or more files
==============================================================

Synopsis
--------
| head [flags] [file ...]

Description
-----------
`head` copies one or more input files to standard output stopping at a
designated point for each file or to the end of the file whichever comes
first. Copying ends at the point indicated by the options. By default a
header of the form `==> `\ *filename*\ ` <==` is output before all but the
first file but this can be changed with the `-q` and `-v` options.

If no *file* is given, or if the *file* is `-`, `head` copies from standard
input starting at the current location.

The option argument for `-c`, and `-s` can optionally be followed by
one of the following characters to specify a different unit other than
a single byte:

:b: 512 bytes.
:k: 1-killobyte.
:m: 1-megabyte.

Flags
-----
For backwards compatibility, `-`\ *number* is equivalent to `-n` *number*.

:-n, --lines=*n*: Copy *n* lines from each file. The default is 10.

:-c, --bytes=*n*: Copy *n* bytes from each file.

:-q, --quiet, --silent: Never output filename headers.

:-s, --skip=*n*: Skip *n* characters or lines from each file before copying.

:-v, --verbose: Always output filename headers.

Exit Status
-----------
0 All files copied successfully.

>0 One or more files did not copy.

See Also
--------
`cat`\(1), `tail`\(1)
@@ -38,6 +38,7 @@ Welcome to the Korn Shell
cmp
cut
dirname
head

Indices and tables
==================

0 comments on commit c584641

Please sign in to comment.
You can’t perform that action at this time.