/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "options.h"
/*
* options
*
* Overview
* sort(1) supports two methods for specifying the sort key: the original,
* now-obsolete, +n -m form and the POSIX -k n,m form. We refer to the former
* as "old specifiers" and the latter as "new specifiers". The options()
* function parses the command line arguments given to sort, placing the sort
* key specifiers in the internal representation used in fields.c.
*
* Equivalence of specifiers
* One of sort(1)'s standard peculiarities is the transformation of the
* character offsets and field numbering between the new and old style field
* specifications. We simply quote from the Single Unix standard:
*
* +w.xT -y.zU
*
* is equivalent to
*
* undefined when z == 0, U contains b, and -t is set
* -k w+1.x+1T,y.0U when z == 0 otherwise
* -k w+1.x+1T,y+1.zU when z > 0
*
* Undoubtedly, this seemed logical at the time. (Using only the field head
* as the coordinate, as done in the obsolete version, seems much simpler.)
* The reverse map is where the key specifier
*
* -k w.xT,y.zU
*
* is equivalent to
*
* undefined when z == 0, U contains b, and -t is set
* +w-1.x-1T,y.0U when z == 0 otherwise
* +w-1.x-1T,y-1.z when z > 0
*
* in the obsolete syntax. Because the original key specifiers lead to a
* simpler implementation, the internal representation of a field in this
* implementation of sort is mostly that given by the obsolete syntax.
*/
/*
* While a key specifier in the obsolete +m ... -n form is being defined (that
* is, before the closing -n is seen), a narrower set of options is permitted.
* We specify this smaller set of options in OLD_SPEC_OPTIONS_STRING.
*/
static int
is_number(char *C)
{
size_t i;
for (i = 0; i < strlen(C); i++)
return (0);
return (1);
}
/*
* If a field specified by the -k option or by the +n syntax contains any
* modifiers, then the current global field modifiers are not inherited.
*/
static int
{
if (p_nonmodifiers == length)
return (0);
return (1);
}
static void
{
field_t *f;
if ((f->f_options & FIELD_MODIFIERS_DEFINED) == 0)
}
static int
{
int field = 0;
int offset = 0;
int offset_seen = 0;
int i;
int blanks_flag = 0;
for (i = 0; i < p_boundary; i++) {
else
return (1);
}
if (p_period < p_modifiers) {
offset_seen++;
} else {
return (1);
}
}
}
if (p_modifiers < length) {
for (i = p_modifiers; i < length; i++) {
switch (C[i]) {
case 'b':
blanks_flag = 1;
break;
case 'd':
F->f_options |= FIELD_DICTIONARY_ORDER;
break;
case 'f':
F->f_options |= FIELD_FOLD_UPPERCASE;
break;
case 'i':
F->f_options |=
break;
case 'M':
break;
case 'n':
break;
case 'r':
F->f_options |=
break;
default:
usage();
break;
}
}
}
if (flags & OPTIONS_STARTSPEC) {
F->f_start_field = field;
F->f_start_offset = offset;
F->f_start_field--;
if (offset_seen)
F->f_start_offset--;
}
} else {
F->f_end_field = field;
F->f_end_offset = offset;
offset_seen && offset != 0)
F->f_end_field--;
}
return (0);
}
static void
{
int p;
/*
* New field specifiers do not inherit from the general specifier if
* they have any modifiers set. (This is specifically tested in the VSC
*/
} else {
}
if (p != 0)
usage();
if (p != 0)
usage();
}
if (S->m_verbose)
}
/*
* If the starting field exceeds a defined ending field, convention
* dictates that the field is ignored.
*/
} else if (S->m_verbose) {
}
}
/*
* parse_old_field_spec() is getopt()-aware; it may modify the values of optind,
* optarg, and so forth, to correctly determine the characteristics being
* assigned to the current field.
*/
static int
{
int c, p;
} else {
}
if (p != 0) {
return (0);
}
/*
* In the case that getopt() returns '?' (unrecognized option) or EOF
* (non-option argument), the field is considered closed.
*/
optind++;
return (1);
}
switch (c) {
case 'b':
break;
case 'd':
break;
case 'f':
break;
case 'i':
break;
case 'M':
break;
case 'n':
break;
case 'r':
break;
case '?':
case 'c':
case 'm':
case 'u':
/*
* Options without arguments.
*/
optind -= 1;
return (1);
/*NOTREACHED*/
case 'o':
case 'T':
case 'z':
case 't':
case 'k':
case 'S':
/*
* Options with arguments.
*/
optind -= 1;
} else {
optind -= 2;
}
return (1);
/*NOTREACHED*/
default:
/*NOTREACHED*/
}
} else {
break;
}
}
return (1);
}
int
{
int c;
optind = 1;
/*
* The -y [kmem] option violates the standard syntax
* outlined in intro(1). we have to be a little fancy
* to determine if the next argument is a valid integer.
* (note, of course, that the previous sort(1) had no
* mechanism to resolve a final
* -y 99999
* into
* -y, file 99999
* or
* -y 99999, file stdin
*
* Now one can unambiguously use
* -y -- 99999
* and
* -y 99999 -
* to distinguish these cases.
*
* That said, we do not use the information passed using
* -y option in sort(1); we provide the argument to
* preserve compatibility for existing scripts.
*/
optind += 2;
else
optind += 1;
}
switch (c) {
case 'c':
S->m_check_if_sorted_only = 1;
break;
case 'm':
S->m_merge_only = 1;
break;
case 'u':
S->m_unique_lines = 1;
break;
case 'o':
S->m_output_filename = optarg;
break;
case 'T':
S->m_tmpdir_template = optarg;
break;
case 'z':
/*
* ignore optarg -- obsolete
*/
break;
case 'd':
break;
case 'f':
break;
case 'i':
S->m_field_options |=
break;
case 'M':
S->m_default_species = MONTH;
S->m_field_options &=
break;
case 'n':
S->m_default_species = NUMERIC;
{
field_t *f;
for (f = S->m_fields_head; f;
f = f->f_next)
if ((f->f_options &
0)
}
break;
case 'b':
S->m_field_options |=
break;
case 'r':
S->m_field_options |=
break;
case 't':
/*
* delimiter
*/
if (S->m_single_byte_locale) {
/*
* Most debuggers can't take tabs as
* input arguments, so we provide an
* escape sequence to allow testing of
* this special case for the DEBUG
* version.
*/
S->m_field_separator.sc =
#ifdef DEBUG
#endif
optarg[0];
} else
optarg, MB_CUR_MAX);
break;
case 'k':
/*
* key
*/
(void) parse_new_field_spec(S, optarg);
break;
case 'S':
#ifdef DEBUG
": limiting size to %d bytes\n",
S->m_memory_limit);
#endif /* DEBUG */
break;
/*
* We never take a naked -999; these should always be
* associated with a preceding +000.
*/
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
usage();
break;
case '?':
/* error case */
usage();
break;
}
/*
* Go back for next argument.
*/
continue;
}
/*
* There are three (interpretable) possibilities for getopt() to
* return EOF with arguments on the command line: we have seen
* the "end-of-options" token, --, we have encountered the
* old-style field definition, +NNN, or we have found a
* filename.
*
* In the second case, we must also search for the optional -NNN
* field terminal definition. (since "+joe", for instance, is
* a valid filename, we must handle this pattern as well.) This
* is performed by parse_old_field_spec().
*/
/*
* Process all arguments following end-of-options token
* as filenames.
*/
S->m_input_from_stdin = 1;
else
&(S->m_input_streams),
optind++;
}
break;
}
S->m_input_from_stdin = 1;
optind++;
/*
* It's a filename, because it either doesn't
* start with '+', or if it did, it wasn't an
* actual field specifier.
*/
optind++;
}
}
}
if (S->m_input_streams == NULL)
S->m_input_from_stdin = 1;
if (S->m_output_filename == NULL)
S->m_output_to_stdout = 1;
/*
* If no fields, then one great field. However, if the -b option was
* set globally, be sure to ignore it, as per UNIX98.
*/
if (S->m_fields_head == NULL) {
(void) parse_new_field_spec(S, "1");
/*
* "Entire line" fast path is only valid if no delimiter has
* been set and no modifiers have been applied.
*/
if (S->m_field_separator.wc == 0 &&
S->m_default_species == ALPHA &&
S->m_field_options == 0)
S->m_entire_line = 1;
}
return (0);
}