<commit_before>#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "config.h"
#include "ignore.h"
#include "options.h"
#include "log.h"
#include "util.h"

/* TODO: printf()ing this is not going to scale */
void usage() {
    printf("Usage: ag [OPTIONS] PATTERN [PATH]\n\
\n\
Recursively search for PATTERN in PATH.\n\
Like grep or ack, but faster.\n\
\n\
Example: ag -i foo /bar/\n\
\n\
Search options:\n\
\n\
--ackmate: Output results in a format parseable by AckMate.\n\
-A --after [LINES]: Print lines before match. Defaults to 2.\n\
-B --before [LINES]: Print lines after match. Defaults to 2.\n\
--[no]break: Print a newline between matches in different files. Enabled by default.\n\
--[no]color: Print color codes in results. Enabled by default.\n\
--column: Print column numbers in results.\n\
-C --context [LINES]: Print lines before and after matches. Defaults to 2.\n\
-D --debug: Ridiculous debugging. Probably not useful.\n\
--depth NUM: Search up to NUM directories deep. Default is 25.\n\
-f --follow: Follow symlinks.\n\
--[no]group: Same as --[no]break --[no]heading\n\
-g PATTERN: Print filenames that match PATTERN\n\
-G, --file-search-regex PATTERN: Only search file names matching PATTERN\n\
-i, --ignore-case\n\
--invert-match\n\
--[no]heading\n\
-l --files-with-matches: Only print filenames containing matches, not matching lines.\n\
-Q --literal: Do not parse PATTERN as a regular expression. Try to match it literally.\n\
-m --max-count NUM: Skip the rest of a file after NUM matches. Default is 10,000.\n\
--print-long-lines: Print matches on very long lines (> 2k characters by default)\n\
--search-binary: Search binary files for matches.\n\
--stats: Print stats (files scanned, time taken, etc)\n\
-w --word-regexp: Only match whole words.\n\
\n");
}

void print_version() {
    printf("ag version %s\n", PACKAGE_VERSION);
}

void init_options() {
    memset(&opts, 0, sizeof(opts));
    opts.casing = CASE_SENSITIVE;
    opts.color = TRUE;
    opts.max_matches_per_file = 10000;
    opts.max_search_depth = 25;
    opts.print_break = TRUE;
    opts.print_heading = TRUE;
    opts.print_line_numbers = TRUE;
    opts.recurse_dirs = TRUE;
}

void cleanup_options() {
    if (opts.query) {
        free(opts.query);
    }

    pcre_free(opts.re);
    if (opts.re_extra) {
         /* Using pcre_free_study on pcre_extra* can segfault on some versions of PCRE */
        pcre_free(opts.re_extra);
    }

    if (opts.ackmate_dir_filter) {
        pcre_free(opts.ackmate_dir_filter);
    }
    if (opts.ackmate_dir_filter_extra) {
        pcre_free(opts.ackmate_dir_filter_extra);
    }

    if (opts.file_search_regex) {
        pcre_free(opts.file_search_regex);
    }
    if (opts.file_search_regex_extra) {
        pcre_free(opts.file_search_regex_extra);
    }
}

void parse_options(int argc, char **argv, char **paths[]) {
    int ch;
    int i;
    int path_len = 0;
    int useless = 0;
    int group = 1;
    int help = 0;
    int version = 0;
    int opt_index = 0;
    const char *home_dir = getenv("HOME");
    char *ignore_file_path = NULL;
    int needs_query = 1;

    init_options();

    struct option longopts[] = {
        { "ackmate", no_argument, &(opts.ackmate), 1 },
        { "ackmate-dir-filter", required_argument, NULL, 0 },
        { "after", required_argument, NULL, 'A' },
        { "all-types", no_argument, NULL, 'a' },
        { "all-text", no_argument, NULL, 't' },
        { "before", required_argument, NULL, 'B' },
        { "break", no_argument, &(opts.print_break), 1 },
        { "nobreak", no_argument, &(opts.print_break), 0 },
        { "color", no_argument, &(opts.color), 1 },
        { "nocolor", no_argument, &(opts.color), 0 },
        { "column", no_argument, &(opts.column), 1 },
        { "context", optional_argument, NULL, 'C' },
        { "debug", no_argument, NULL, 'D' },
        { "depth", required_argument, NULL, 0 },
        { "follow", no_argument, &(opts.follow_symlinks), 1 },
        { "file-search-regex", required_argument, NULL, 'G' },
        { "group", no_argument, &(group), 1 },
        { "nogroup", no_argument, &(group), 0 },
        { "hidden", no_argument, &(opts.search_hidden_files), 1 },
        { "invert-match", no_argument, &(opts.invert_match), 1 },
        { "nofollow", no_argument, &(opts.follow_symlinks), 0 },
        { "heading", no_argument, &(opts.print_heading), 1 },
        { "noheading", no_argument, &(opts.print_heading), 0 },
        { "no-recurse", no_argument, NULL, 'n' },
        { "help", no_argument, NULL, 'h' },
        { "ignore-case", no_argument, NULL, 'i' },
        { "files-with-matches", no_argument, NULL, 'l' },
        { "files-without-matches", no_argument, NULL, 'L' },
        { "literal", no_argument, NULL, 'Q' },
        { "match", no_argument, &useless, 0 },
        { "max-count", required_argument, NULL, 'm' },
        { "parallel", no_argument, &(opts.parallel), 1},
        { "print-long-lines", no_argument, &(opts.print_long_lines), 1 },
        { "recurse", no_argument, NULL, 'r' },
        { "search-binary", no_argument, &(opts.search_binary_files), 1 },
        { "search-files", no_argument, &(opts.search_stream), 0 },
        { "case-sensitive", no_argument, NULL, 's' },
        { "smart-case", no_argument, NULL, 'S' },
        { "stats", no_argument, &(opts.stats), 1 },
        { "unrestricted", no_argument, NULL, 'u' },
        { "skip-vcs-ignores", no_argument, NULL, 'U' },
        { "version", no_argument, &version, 1 },
        { "word-regexp", no_argument, NULL, 'w' },
        { "workers", required_argument, NULL, 0 },<commit_msg>Sort these options.<commit_after>#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "config.h"
#include "ignore.h"
#include "options.h"
#include "log.h"
#include "util.h"

/* TODO: printf()ing this is not going to scale */
void usage() {
    printf("Usage: ag [OPTIONS] PATTERN [PATH]\n\
\n\
Recursively search for PATTERN in PATH.\n\
Like grep or ack, but faster.\n\
\n\
Example: ag -i foo /bar/\n\
\n\
Search options:\n\
\n\
--ackmate: Output results in a format parseable by AckMate.\n\
-A --after [LINES]: Print lines before match. Defaults to 2.\n\
-B --before [LINES]: Print lines after match. Defaults to 2.\n\
--[no]break: Print a newline between matches in different files. Enabled by default.\n\
--[no]color: Print color codes in results. Enabled by default.\n\
--column: Print column numbers in results.\n\
-C --context [LINES]: Print lines before and after matches. Defaults to 2.\n\
-D --debug: Ridiculous debugging. Probably not useful.\n\
--depth NUM: Search up to NUM directories deep. Default is 25.\n\
-f --follow: Follow symlinks.\n\
--[no]group: Same as --[no]break --[no]heading\n\
-g PATTERN: Print filenames that match PATTERN\n\
-G, --file-search-regex PATTERN: Only search file names matching PATTERN\n\
-i, --ignore-case\n\
--invert-match\n\
--[no]heading\n\
-l --files-with-matches: Only print filenames containing matches, not matching lines.\n\
-Q --literal: Do not parse PATTERN as a regular expression. Try to match it literally.\n\
-m --max-count NUM: Skip the rest of a file after NUM matches. Default is 10,000.\n\
--print-long-lines: Print matches on very long lines (> 2k characters by default)\n\
--search-binary: Search binary files for matches.\n\
--stats: Print stats (files scanned, time taken, etc)\n\
-w --word-regexp: Only match whole words.\n\
\n");
}

void print_version() {
    printf("ag version %s\n", PACKAGE_VERSION);
}

void init_options() {
    memset(&opts, 0, sizeof(opts));
    opts.casing = CASE_SENSITIVE;
    opts.color = TRUE;
    opts.max_matches_per_file = 10000;
    opts.max_search_depth = 25;
    opts.print_break = TRUE;
    opts.print_heading = TRUE;
    opts.print_line_numbers = TRUE;
    opts.recurse_dirs = TRUE;
}

void cleanup_options() {
    if (opts.query) {
        free(opts.query);
    }

    pcre_free(opts.re);
    if (opts.re_extra) {
         /* Using pcre_free_study on pcre_extra* can segfault on some versions of PCRE */
        pcre_free(opts.re_extra);
    }

    if (opts.ackmate_dir_filter) {
        pcre_free(opts.ackmate_dir_filter);
    }
    if (opts.ackmate_dir_filter_extra) {
        pcre_free(opts.ackmate_dir_filter_extra);
    }

    if (opts.file_search_regex) {
        pcre_free(opts.file_search_regex);
    }
    if (opts.file_search_regex_extra) {
        pcre_free(opts.file_search_regex_extra);
    }
}

void parse_options(int argc, char **argv, char **paths[]) {
    int ch;
    int i;
    int path_len = 0;
    int useless = 0;
    int group = 1;
    int help = 0;
    int version = 0;
    int opt_index = 0;
    const char *home_dir = getenv("HOME");
    char *ignore_file_path = NULL;
    int needs_query = 1;

    init_options();

    struct option longopts[] = {
        { "ackmate", no_argument, &(opts.ackmate), 1 },
        { "ackmate-dir-filter", required_argument, NULL, 0 },
        { "after", required_argument, NULL, 'A' },
        { "all-text", no_argument, NULL, 't' },
        { "all-types", no_argument, NULL, 'a' },
        { "before", required_argument, NULL, 'B' },
        { "break", no_argument, &(opts.print_break), 1 },
        { "case-sensitive", no_argument, NULL, 's' },
        { "color", no_argument, &(opts.color), 1 },
        { "column", no_argument, &(opts.column), 1 },
        { "context", optional_argument, NULL, 'C' },
        { "debug", no_argument, NULL, 'D' },
        { "depth", required_argument, NULL, 0 },
        { "file-search-regex", required_argument, NULL, 'G' },
        { "files-with-matches", no_argument, NULL, 'l' },
        { "files-without-matches", no_argument, NULL, 'L' },
        { "follow", no_argument, &(opts.follow_symlinks), 1 },
        { "group", no_argument, &(group), 1 },
        { "heading", no_argument, &(opts.print_heading), 1 },
        { "help", no_argument, NULL, 'h' },
        { "hidden", no_argument, &(opts.search_hidden_files), 1 },
        { "ignore-case", no_argument, NULL, 'i' },
        { "invert-match", no_argument, &(opts.invert_match), 1 },
        { "literal", no_argument, NULL, 'Q' },
        { "match", no_argument, &useless, 0 },
        { "max-count", required_argument, NULL, 'm' },
        { "no-recurse", no_argument, NULL, 'n' },
        { "nobreak", no_argument, &(opts.print_break), 0 },
        { "nocolor", no_argument, &(opts.color), 0 },
        { "nofollow", no_argument, &(opts.follow_symlinks), 0 },
        { "nogroup", no_argument, &(group), 0 },
        { "noheading", no_argument, &(opts.print_heading), 0 },
        { "parallel", no_argument, &(opts.parallel), 1},
        { "print-long-lines", no_argument, &(opts.print_long_lines), 1 },
        { "recurse", no_argument, NULL, 'r' },
        { "search-binary", no_argument, &(opts.search_binary_files), 1 },
        { "search-files", no_argument, &(opts.search_stream), 0 },
        { "skip-vcs-ignores", no_argument, NULL, 'U' },
        { "smart-case", no_argument, NULL, 'S' },
        { "stats", no_argument, &(opts.stats), 1 },
        { "unrestricted", no_argument, NULL, 'u' },
        { "version", no_argument, &version, 1 },
        { "word-regexp", no_argument, NULL, 'w' },
        { "workers", required_argument, NULL, 0 },
{'fraction_non_alphanumeric': 0.16455584872471415, 'fraction_numerical': 0.008795074758135445, 'mean_word_length': 2.8729564032697548, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5060476', 'n_tokens_mistral': 4029, 'n_tokens_neox': 3900, 'n_words': 1052}