Beispiel #1
0
int
main(int argc, char *argv[])
{
    int ch, i, stdinflag = 0;
    char cflag = 0, mflag = 0;
    char *outfile, *outpath = NULL;
    struct field *fldtab;
    size_t fldtab_sz, fld_cnt;
    size_t alloc_size;
    struct filelist filelist;
    int num_input_files;
    FILE *outfp = NULL;
    struct rlimit rl;
    struct stat st;

    setlocale(LC_ALL, "");

    /* bump RLIMIT_NOFILE to maximum our hard limit allows */
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
        err(2, "getrlimit");
    rl.rlim_cur = rl.rlim_max;
    if (setrlimit(RLIMIT_NOFILE, &rl) < 0)
        err(2, "setrlimit");

    d_mask[REC_D = '\n'] = REC_D_F;
    d_mask['\t'] = d_mask[' '] = BLANK | FLD_D;

    /* fldtab[0] is the global options. */
    fldtab_sz = 3;
    fld_cnt = 0;
    alloc_size = fldtab_sz * sizeof(*fldtab);
    fldtab = malloc(alloc_size);
    if (fldtab == NULL)
        err(1, "Cannot allocate %zu bytes", alloc_size);
    memset(fldtab, 0, alloc_size);

#define SORT_OPTS "bcdD:fHik:lmno:rR:sSt:T:ux"

    /* Convert "+field" args to -f format */
    fixit(&argc, argv, SORT_OPTS);

    if (!(tmpdir = getenv("TMPDIR")))
        tmpdir = _PATH_TMP;

    while ((ch = getopt(argc, argv, SORT_OPTS)) != -1) {
        switch (ch) {
        case 'b':
            fldtab[0].flags |= BI | BT;
            break;
        case 'c':
            cflag = 1;
            break;
        case 'D': /* Debug flags */
            for (i = 0; optarg[i]; i++)
                debug_flags |= 1 << (optarg[i] & 31);
            break;
        case 'd':
        case 'f':
        case 'i':
        case 'n':
        case 'l':
            fldtab[0].flags |= optval(ch, 0);
            break;
        case 'H':
            /* -H was ; use merge sort for blocks of large files' */
            /* That is now the default. */
            break;
        case 'k':
            alloc_size = (fldtab_sz + 1) * sizeof(*fldtab);
            fldtab = realloc(fldtab, alloc_size);
            if (fldtab == NULL)
                err(1, "Cannot re-allocate %zu bytes", alloc_size);
            memset(&fldtab[fldtab_sz], 0, sizeof(fldtab[0]));
            fldtab_sz++;

            setfield(optarg, &fldtab[++fld_cnt], fldtab[0].flags);
            break;
        case 'm':
            mflag = 1;
            break;
        case 'o':
            outpath = optarg;
            break;
        case 'r':
            REVERSE = 1;
            break;
        case 's':
            /*
             * Nominally 'stable sort', keep lines with equal keys
             * in input file order. (Default for NetBSD)
             * (-s for GNU sort compatibility.)
             */
            posix_sort = 0;
            break;
        case 'S':
            /*
             * Reverse of -s!
             * This needs to enforce a POSIX sort where records
             * with equal keys are then sorted by the raw data.
             * Currently not implemented!
             * (using libc radixsort() v sradixsort() doesn't
             * have the desired effect.)
             */
            posix_sort = 1;
            break;
        case 't':
            if (SEP_FLAG)
                usage("multiple field delimiters");
            SEP_FLAG = 1;
            d_mask[' '] &= ~FLD_D;
            d_mask['\t'] &= ~FLD_D;
            d_mask[(u_char)*optarg] |= FLD_D;
            if (d_mask[(u_char)*optarg] & REC_D_F)
                errx(2, "record/field delimiter clash");
            break;
        case 'R':
            if (REC_D != '\n')
                usage("multiple record delimiters");
            REC_D = *optarg;
            if (REC_D == '\n')
                break;
            if (optarg[1] != '\0') {
                char *ep;
                int t = 0;
                if (optarg[0] == '\\')
                    optarg++, t = 8;
                REC_D = (int)strtol(optarg, &ep, t);
                if (*ep != '\0' || REC_D < 0 ||
                        REC_D >= (int)__arraycount(d_mask))
                    errx(2, "invalid record delimiter %s",
                         optarg);
            }
            d_mask['\n'] = d_mask[' '];
            d_mask[REC_D] = REC_D_F;
            break;
        case 'T':
            /* -T tmpdir */
            tmpdir = optarg;
            break;
        case 'u':
            UNIQUE = 1;
            break;
        case '?':
        default:
            usage(NULL);
        }
    }

    if (UNIQUE)
        /* Don't sort on raw record if keys match */
        posix_sort = 0;

    if (cflag && argc > optind+1)
        errx(2, "too many input files for -c option");
    if (argc - 2 > optind && !strcmp(argv[argc-2], "-o")) {
        outpath = argv[argc-1];
        argc -= 2;
    }
    if (mflag && argc - optind > (MAXFCT - (16+1))*16)
        errx(2, "too many input files for -m option");

    for (i = optind; i < argc; i++) {
        /* allow one occurrence of /dev/stdin */
        if (!strcmp(argv[i], "-") || !strcmp(argv[i], _PATH_STDIN)) {
            if (stdinflag)
                warnx("ignoring extra \"%s\" in file list",
                      argv[i]);
            else
                stdinflag = 1;

            /* change to /dev/stdin if '-' */
            if (argv[i][0] == '-') {
                static char path_stdin[] = _PATH_STDIN;
                argv[i] = path_stdin;
            }

        } else if ((ch = access(argv[i], R_OK)))
            err(2, "%s", argv[i]);
    }

    if (fldtab[1].icol.num == 0) {
        /* No sort key specified */
        if (fldtab[0].flags & (I|D|F|N|L)) {
            /* Modified - generate a key that covers the line */
            fldtab[0].flags &= ~(BI|BT);
            setfield("1", &fldtab[++fld_cnt], fldtab->flags);
            fldreset(fldtab);
        } else {
            /* Unmodified, just compare the line */
            SINGL_FLD = 1;
            fldtab[0].icol.num = 1;
        }
    } else {
        fldreset(fldtab);
    }

    settables();

    if (optind == argc) {
        static const char * const names[] = { _PATH_STDIN, NULL };
        filelist.names = names;
        num_input_files = 1;
    } else {
        filelist.names = (const char * const *) &argv[optind];
        num_input_files = argc - optind;
    }

    if (cflag) {
        order(&filelist, fldtab);
        /* NOT REACHED */
    }

    if (!outpath) {
        toutpath[0] = '\0';	/* path not used in this case */
        outfile = outpath = toutpath;
        outfp = stdout;
    } else if (lstat(outpath, &st) == 0
               && !S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
        /* output file exists and isn't character or block device */
        struct sigaction act;
        static const int sigtable[] = {SIGHUP, SIGINT, SIGPIPE,
                                       SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, 0
                                      };
        int outfd;
        errno = 0;
        if (access(outpath, W_OK))
            err(2, "%s", outpath);
        (void)snprintf(toutpath, sizeof(toutpath), "%sXXXXXX",
                       outpath);
        if ((outfd = mkstemp(toutpath)) == -1)
            err(2, "Cannot create temporary file `%s'", toutpath);
        (void)atexit(cleanup);
        act.sa_handler = onsignal;
        (void) sigemptyset(&act.sa_mask);
        act.sa_flags = SA_RESTART | SA_RESETHAND;
        for (i = 0; sigtable[i]; ++i)	/* always unlink toutpath */
            sigaction(sigtable[i], &act, 0);
        outfile = toutpath;
        if ((outfp = fdopen(outfd, "w")) == NULL)
            err(2, "Cannot open temporary file `%s'", toutpath);
    } else {
        outfile = outpath;

        if ((outfp = fopen(outfile, "w")) == NULL)
            err(2, "output file %s", outfile);
    }

    if (mflag)
        fmerge(&filelist, num_input_files, outfp, fldtab);
    else
        fsort(&filelist, num_input_files, outfp, fldtab);

    if (outfile != outpath) {
        if (access(outfile, F_OK))
            err(2, "%s", outfile);

        /*
         * Copy file permissions bits of the original file.
         * st is initialized above, when we create the
         * temporary spool file.
         */
        if (lchmod(outfile, st.st_mode & ALLPERMS) != 0) {
            err(2, "cannot chmod %s: output left in %s",
                outpath, outfile);
        }

        (void)unlink(outpath);
        if (link(outfile, outpath))
            err(2, "cannot link %s: output left in %s",
                outpath, outfile);
        (void)unlink(outfile);
        toutpath[0] = 0;
    }
    exit(0);
}
Beispiel #2
0
  bool OptionsList::SetStringValue(const std::string& tag,
                                   const std::string& value,
                                   bool allow_clobber, /* = true */
                                   bool dont_print /* = false */)
  {
    if (IsValid(reg_options_)) {
      SmartPtr<const RegisteredOption> option = reg_options_->GetOption(tag);

      if (IsNull(option)) {
        if (IsValid(jnlst_)) {
          std::string msg = "Tried to set Option: " + tag;
          msg += ". It is not a valid option. Please check the list of available options.\n";
          jnlst_->Printf(J_ERROR, J_MAIN, msg.c_str());
        }
        //THROW_EXCEPTION(OPTION_INVALID, msg);
        return false;
      }

      if (option->Type() != OT_String) {
        if (IsValid(jnlst_)) {
          std::string msg = "Tried to set Option: " + tag;
          msg += ". It is a valid option, but it is of type ";
          if (option->Type() == OT_Number) {
            msg += " Number";
          }
          else if (option->Type() == OT_Integer) {
            msg += " Integer";
          }
          else {
            msg += " Unknown";
          }
          msg += ", not of type String. Please check the documentation for options.\n";
          jnlst_->Printf(J_ERROR, J_MAIN, msg.c_str());
          option->OutputDescription(*jnlst_);
        }
        //THROW_EXCEPTION(OPTION_INVALID, msg);
        return false;
      }

      if (!option->IsValidStringSetting(value)) {
        if (IsValid(jnlst_)) {
          std::string msg = "Setting: " + value;
          msg += " is not a valid setting for Option: ";
          msg += tag;
          msg += ". Check the option documentation.\n";
          jnlst_->Printf(J_ERROR, J_MAIN, msg.c_str());
          option->OutputDescription(*jnlst_);
        }
        //THROW_EXCEPTION(OPTION_INVALID, msg);
        return false;
      }
    }

    if (!will_allow_clobber(tag)) {
      if (IsValid(jnlst_)) {
        std::string msg = "WARNING: Tried to set option \"" + tag;
        msg += "\" to a value of \"" + value;
        msg += "\",\n         but the previous value is set to disallow clobbering.\n";
        msg += "         The setting will remain as: \"" + tag;
        msg += " " + options_[lowercase(tag)].GetValue();
        msg += "\"\n";
        jnlst_->Printf(J_WARNING, J_MAIN, msg.c_str());
      }
    }
    else {
      //    if (will_allow_clobber(tag)) {
      OptionsList::OptionValue optval(lowercase(value), allow_clobber,
                                      dont_print);
      options_[lowercase(tag)] = optval;
    }
    return true;

    //     std::string msg = "Option: \"" + tag;
    //     msg += " ";
    //     msg += value;
    //     msg += "\" not taken because a value of \n\"" ;
    //     msg += options_[lowercase(tag)].GetValue();
    //     msg += "\" already exists and is set to disallow clobbering.\n\n";
    //     jnlst_->Printf(J_ERROR, J_MAIN, msg.c_str());
    //     return false;
  }