সি-তে কমান্ড-লাইন যুক্তি পার্সিং করছেন?


103

আমি এমন একটি প্রোগ্রাম লেখার চেষ্টা করছি যা দুটি লাইন লাইন, শব্দ থেকে বা একটি বর্ণের বর্ণ সি এর সাথে তুলনা করতে পারে। এটি কমান্ড লাইনের বিকল্পগুলিতে পড়তে সক্ষম হতে হবে -l -w -i or --...

  • অপশনটি যদি -l হয় তবে এটি লাইন দ্বারা ফাইলগুলি লাইন তুলনা করে।
  • অপশনটি যদি -w হয় তবে এটি শব্দ শব্দের সাথে ফাইলের তুলনা করে।
  • বিকল্পগুলি যদি হয় - এটি স্বয়ংক্রিয়ভাবে ধরে নেয় যে পরবর্তী আরগটি প্রথম ফাইলের নাম।
  • বিকল্পটি যদি -i হয় তবে এটি তাদের সাথে সংবেদনশীল উপায়ে তুলনা করে।
  • অক্ষর অনুসারে ফাইলের অক্ষর তুলনা করতে ডিফল্ট।

-W এবং -l একই সময়ে ইনপুট করা না হওয়া পর্যন্ত অপশনগুলি কতবার ইনপুট হবে তা বিবেচনা করার কথা নয় এবং 2 টিরও বেশি বা কম ফাইল নেই।

কমান্ড লাইন আর্গুমেন্টগুলি বিশ্লেষণ করে কোথায় শুরু করতে হবে তা আমি জানি না। সাহায্য করুন :(

সুতরাং এই কোডটিই আমি নিয়ে এসেছি সব কিছুর জন্য। আমি এখনও এটি ত্রুটি করে দেখিনি, তবে আমি ভাবছিলাম যে আমি কী খুব বেশি জটিল পদ্ধতিতে লিখছি?

/*
 * Functions to compare files.
 */
int compare_line();
int compare_word();
int compare_char();
int case_insens();

/*
 * Program to compare the information in two files and print message saying 
 * whether or not this was successful.
 */
int main(int argc, char* argv[])
{
/*Loop counter*/
  size_t i = 0;

  /*Variables for functions*/
  int caseIns = 0;
  int line = 0;
  int word = 0;

  /*File pointers*/
  FILE *fp1, *fp2;

  /*
   * Read through command-line arguments for options.
   */
  for (i = 1; i < argc; i++) {
    printf("argv[%u] = %s\n", i, argv[i]);
    if (argv[i][0] == '-') {
       if (argv[i][1] == 'i') 
       {
           caseIns = 1;
       }
       if (argv[i][1] == 'l')
       {
           line = 1;
       }
       if (argv[i][1] == 'w')
       {
           word = 1;
       }
       if (argv[i][1] == '-')
       {
           fp1 = argv[i][2];
           fp2 = argv[i][3];
       }
       else 
       {
           printf("Invalid option.");
           return 2;
       }
    } else {
       fp1(argv[i]);
       fp2(argv[i][1]);
    }
  }

  /*
   * Check that files can be opened.
   */
  if(((fp1 = fopen(fp1, "rb")) ==  NULL) || ((fp2 = fopen(fp2, "rb")) == NULL))
  {
      perror("fopen()");
      return 3;
  }
  else{
        if (caseIns == 1)
        {
            if(line == 1 && word == 1)
            {
                printf("That is invalid.");
                return 2;
            }
            if(line == 1 && word == 0)
            {
                if(compare_line(case_insens(fp1, fp2)) == 0)
                        return 0;
            }
            if(line == 0 && word == 1)
            {
                if(compare_word(case_insens(fp1, fp2)) == 0)
                    return 0;
            }
            else
            {
                if(compare_char(case_insens(fp1,fp2)) == 0)
                    return 0;
            }
        }
        else
        {
            if(line == 1 && word == 1)
            {
                printf("That is invalid.");
                return 2;
            }
            if(line == 1 && word == 0)
            {
                if(compare_line(fp1, fp2) == 0)
                    return 0;
            }
            if(line == 0 && word == 1)
            {
                if(compare_word(fp1, fp2) == 0)
                    return 0;
            }
            else
            {
                if(compare_char(fp1, fp2) == 0)
                    return 0;
            }
        }

  }
    return 1;
    if(((fp1 = fclose(fp1)) == NULL) || (((fp2 = fclose(fp2)) == NULL)))
        {
            perror("fclose()");
            return 3;
        }
        else
        {
            fp1 = fclose(fp1);
            fp2 = fclose(fp2);
        }
}

/*
 * Function to compare two files line-by-line.
 */
int compare_line(FILE *fp1, FILE *fp2)
{
    /*Buffer variables to store the lines in the file*/
    char buff1 [LINESIZE];
    char buff2 [LINESIZE];

    /*Check that neither is the end of file*/
    while((!feof(fp1)) && (!feof(fp2)))
    {
        /*Go through files line by line*/
        fgets(buff1, LINESIZE, fp1);
        fgets(buff2, LINESIZE, fp2);
    }
    /*Compare files line by line*/
    if(strcmp(buff1, buff2) == 0)
    {
        printf("Files are equal.\n");
        return 0;
    }
    printf("Files are not equal.\n");
    return 1;
}   

/*
 * Function to compare two files word-by-word.
 */
int compare_word(FILE *fp1, FILE *fp2)
{
    /*File pointers*/
    FILE *fp1, *fp2;

    /*Arrays to store words*/
    char fp1words[LINESIZE];
    char fp2words[LINESIZE];

    if(strtok(fp1, " ") == NULL || strtok(fp2, " ") == NULL)
    {
        printf("File is empty. Cannot compare.\n");
        return 0;
    }
    else
    {
        fp1words = strtok(fp1, " ");
        fp2words = strtok(fp2, " ");

        if(fp1words == fp2words)
        {
            fputs(fp1words);
            fputs(fp2words);
            printf("Files are equal.\n");
            return 0;
        }
    }
    return 1;
}

/*
 * Function to compare two files character by character.
 */
int compare_char(FILE *fp1,FILE *fp2)
{
    /*Variables to store the characters from both files*/
    int c;
    int d;

    /*Buffer variables to store chars*/
    char buff1 [LINESIZE];
    char buff2 [LINESIZE];

    while(((c = fgetc(fp1))!= EOF) && (((d = fgetc(fp2))!=EOF)))
    {
        if(c == d)
        {
            if((fscanf(fp1, "%c", buff1)) == (fscanf(fp2, "%c", buff2)))
            {
                printf("Files have equivalent characters.\n");
                return 1;
                break;
            }
        }

    }
        return 0;
}

/*
 * Function to compare two files in a case-insensitive manner.
 */
int case_insens(FILE *fp1, FILE *fp2, size_t n)
{
    /*Pointers for files.*/
    FILE *fp1, *fp2;

    /*Variable to go through files.*/
    size_t i = 0;

    /*Arrays to store file information.*/
    char fp1store[LINESIZE];
    char fp2store[LINESIZE];

    while(!feof(fp1) && !feof(fp2))
    {
         for(i = 0; i < n; i++)
         {
                fscanf(fp1, "%s", fp1store);
                fscanf(fp2, "%s", fp2store);

                fp1store = tolower(fp1store);
                fp2store = tolower(fp2store);

                return 1;
         }
    }
    return 0;
}

আমি কীভাবে getopt () ব্যবহার করব তা সম্পর্কে আমি নিশ্চিত নই ... আমি আমার ক্লাসে এখনও এটি সম্পর্কে জানতে পারি নি।
ব্যবহারকারী 1251020

4
সুতরাং, যান এবং এর জন্য ম্যানুয়াল পৃষ্ঠাটি পড়ুন; এটি খুব জটিল নয়, এবং ম্যানুয়াল পৃষ্ঠাতে সম্ভবত আপনি পরীক্ষার জন্য একটি উদাহরণ অন্তর্ভুক্ত করেছেন (এবং যদি আপনার স্থানীয় ম্যান পৃষ্ঠাটি না থাকে তবে আপনি অবশ্যই ওয়েবে উদাহরণ খুঁজে পেতে পারেন)।
জোনাথন লেফলার

4
এটি একটি উচ্চ স্তরের লাইব্রেরি: আরগপার্স সি তে, সহজেই ব্যবহারযোগ্য।
কফাইক


সাধারণ স্টাফের জন্য আপনি কেবল গ্রন্থাগার ব্যবহার না করে নিজের রোল করতে পারেন। আমি শুরু টিউটোরিয়াল এখানে লিখেছিলেন engineeringterminal.com/computer-science/tutorials/...
nalyd88

উত্তর:


192

আমার জানা মতে, সি-তে কমান্ড লাইন যুক্তিগুলি পার্স করার জন্য তিনটি সর্বাধিক জনপ্রিয় উপায় হ'ল:

  • Getopt ( পসিক্স#include <unistd.h> সি লাইব্রেরি থেকে), যা সাধারণ যুক্তি পার্সিংয়ের কার্যগুলি সমাধান করতে পারে । আপনি যদি বাশের সাথে কিছুটা পরিচিত হন তবে ব্যাশটির অন্তর্নির্মিত গেটপটটি জিএনইউ লাইব্যাক থেকে প্রাপ্ত গেটপটের উপর ভিত্তি করে।
  • আরজিপি ( #include <argp.h>জিএনইউ সি লাইব্রেরি থেকে), যা আরও জটিল কাজগুলি সমাধান করতে পারে এবং স্টাফের যত্ন নেয় যেমন, উদাহরণস্বরূপ:
    • -?, ইমেল ঠিকানা সহ সহায়তা বার্তার--help জন্য
    • -V, --versionজন্য সংস্করণ তথ্য
    • --usageজন্য ব্যবহার বার্তা
  • এটি নিজেই করা , যা আমি অন্য কোনও প্রোগ্রামকে দেওয়া প্রোগ্রামগুলির জন্য প্রস্তাব দিই না, কারণ এমন অনেক কিছুই আছে যা ভুল বা নিম্নমানের হতে পারে। অপশন পার্সিং বন্ধ করতে '-' ভুলে যাওয়ার জনপ্রিয় ভুল মাত্র একটি উদাহরণ।

জিএনইউ সি লাইব্রেরি ডকুমেন্টেশনে গেটোপ্ট এবং আরগ্পের জন্য কয়েকটি দুর্দান্ত উদাহরণ রয়েছে।

গেটপট ব্যবহারের জন্য উদাহরণ

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
    bool isCaseInsensitive = false;
    int opt;
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;

    while ((opt = getopt(argc, argv, "ilw")) != -1) {
        switch (opt) {
        case 'i': isCaseInsensitive = true; break;
        case 'l': mode = LINE_MODE; break;
        case 'w': mode = WORD_MODE; break;
        default:
            fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    // Now optind (declared extern int by <unistd.h>) is the index of the first non-option argument.
    // If it is >= argc, there were no non-option arguments.

    // ...
}

আরগ্প ব্যবহারের জন্য উদাহরণ

#include <argp.h>
#include <stdbool.h>

const char *argp_program_version = "programname programversion";
const char *argp_program_bug_address = "<your@email.address>";
static char doc[] = "Your program description.";
static char args_doc[] = "[FILENAME]...";
static struct argp_option options[] = { 
    { "line", 'l', 0, 0, "Compare lines instead of characters."},
    { "word", 'w', 0, 0, "Compare words instead of characters."},
    { "nocase", 'i', 0, 0, "Compare case insensitive instead of case sensitive."},
    { 0 } 
};

struct arguments {
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode;
    bool isCaseInsensitive;
};

static error_t parse_opt(int key, char *arg, struct argp_state *state) {
    struct arguments *arguments = state->input;
    switch (key) {
    case 'l': arguments->mode = LINE_MODE; break;
    case 'w': arguments->mode = WORD_MODE; break;
    case 'i': arguments->isCaseInsensitive = true; break;
    case ARGP_KEY_ARG: return 0;
    default: return ARGP_ERR_UNKNOWN;
    }   
    return 0;
}

static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 };

int main(int argc, char *argv[])
{
    struct arguments arguments;

    arguments.mode = CHARACTER_MODE;
    arguments.isCaseInsensitive = false;

    argp_parse(&argp, argc, argv, 0, 0, &arguments);

    // ...
}

এটি নিজে করার জন্য উদাহরণ

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{   
    bool isCaseInsensitive = false;
    enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;
    size_t optind;
    for (optind = 1; optind < argc && argv[optind][0] == '-'; optind++) {
        switch (argv[optind][1]) {
        case 'i': isCaseInsensitive = true; break;
        case 'l': mode = LINE_MODE; break;
        case 'w': mode = WORD_MODE; break;
        default:
            fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
            exit(EXIT_FAILURE);
        }   
    }   

    // *argv points to the remaining non-option arguments.
    // If *argv is NULL, there were no non-option arguments.

    // ...
}   

দাবি অস্বীকার: আমি আরগ্পে নতুন, উদাহরণটিতে ত্রুটি থাকতে পারে।


9
সত্যিই পুরো উত্তর, ধন্যবাদ খ্রিস্টান (উত্সাহিত) যাইহোক, ম্যাক ব্যবহারকারীদের সচেতন হওয়া উচিত যে আরগপি পদ্ধতিটি ক্রস প্ল্যাটফর্মের সাথে সামঞ্জস্যপূর্ণ নয়। যেমনটি আমি এখানে পেয়েছি , আরগ্প হ'ল একটি মানহীন গ্লিবসি এপিআই এক্সটেনশন। এটি gnulibউপলব্ধ তাই স্পষ্টভাবে একটি প্রকল্পে যুক্ত করা যেতে পারে। তবে ম্যাক-কেবলমাত্র বা ক্রস-প্ল্যাটফর্ম ডেভেলপারদের গিওপট পদ্ধতির ব্যবহার করা সম্ভবত এটি সহজ।
thclark

4
এটি নিজেই করুন সংস্করণটির জন্য, আমি পছন্দ করি না যে বিকল্পগুলি পরে অতিরিক্ত পাঠ্যকে মঞ্জুরি দেয়, যেমন -wzzz -W হিসাবে একই পার্স করে এবং ফাইল আর্গুমেন্টের আগে বিকল্পগুলি আসতে হবে।
জেক

4
@ জ্যাক আপনি ঠিক বলেছেন। যে স্পট জন্য সম্মান। আমি কখনই এটি লিখেছিলাম তা আমি মনে করেছি কিনা মনে নেই I এটি আবার একটি নিখুঁত উদাহরণ যে DIY ভুল পেতে এত সহজ এবং সুতরাং এটি করা উচিত নয়। বলার জন্য ধন্যবাদ, আমি উদাহরণ ঠিক করতে পারে।
খ্রিস্টান হুজার

18

ব্যবহার করুন getopt(), বা সম্ভবত getopt_long()

int iflag = 0;
enum { WORD_MODE, LINE_MODE } op_mode = WORD_MODE;  // Default set
int opt;

while ((opt = getopt(argc, argv, "ilw") != -1)
{
    switch (opt)
    {
    case 'i':
        iflag = 1;
        break;
    case 'l':
        op_mode = LINE_MODE;
        break;
    case 'w':
        op_mode = WORD_MODE;
        break;
    default:
        fprintf(stderr, "Usage: %s [-ilw] [file ...]\n", argv[0]);
        exit(EXIT_FAILURE);
    }
}

/* Process file names or stdin */
if (optind >= argc)
    process(stdin, "(standard input)", op_mode);
else
{
    int i;
    for (i = optind; i < argc; i++)
    {
        FILE *fp = fopen(argv[i], "r");
        if (fp == 0)
            fprintf(stderr, "%s: failed to open %s (%d %s)\n",
                    argv[0], argv[i], errno, strerror(errno));
        else
        {
            process(fp, argv[i], op_mode);
            fclose(fp);
        }
    }
 }

নোট করুন যে কোন শিরোনামকে অন্তর্ভুক্ত করতে হবে তা নির্ধারণ করতে হবে (আমি এটি প্রয়োজনীয়ভাবে তৈরি করব 4) এবং আমি যেভাবে op_modeটাইপটি লিখেছি তার অর্থ ফাংশনে আপনার কোনও সমস্যা আছে process()- আপনি সেখানে অঙ্কটি অ্যাক্সেস করতে পারবেন না। কার্যটির বাইরে অঙ্কটি সরিয়ে নেওয়া ভাল; এমনকি আপনি op_modeকোনও ফাইল-স্কোপকে ভেরিয়েবলটি বহিরাগত সংযোগ ছাড়াই তৈরি করতে পারেন (বলার অভিনব উপায় static) যাতে এটি ফাংশনে না এড়ানো যায়। এই কোডটি -স্ট্যান্ডার্ড ইনপুট প্রতিশব্দ হিসাবে হ্যান্ডেল করে না , পাঠকের জন্য অন্য একটি অনুশীলন। মনে রাখবেন যে আপনার জন্য বিকল্পগুলির শেষ চিহ্নিত করতে getopt()স্বয়ংক্রিয়ভাবে যত্ন নেওয়া হয় --

আমি একটি সংকলক অতীত উপরের টাইপিংয়ের কোনও সংস্করণ চালিয়েছি না; এটিতে ভুল হতে পারে।


অতিরিক্ত creditণের জন্য, একটি (গ্রন্থাগার) ফাংশন লিখুন:

int filter(int argc, char **argv, int idx, int (*function)(FILE *fp, const char *fn));

যা getopt()লুপের পরে ফাইলের নাম বিকল্পগুলির প্রক্রিয়াকরণের জন্য যুক্তিকে আবদ্ধ করে । এটি -স্ট্যান্ডার্ড ইনপুট হিসাবে হ্যান্ডেল করা উচিত । নোট করুন যে এটি ব্যবহার করে এটি নির্দেশ করে যে op_modeএটি একটি স্ট্যাটিক ফাইল স্কোপ ভেরিয়েবল। দ্যfilter()ফাংশন লাগে argc, argv, optindএবং প্রক্রিয়াকরণ ফাংশন একটি পয়েন্টার। এটি 0 (EXIT_SUCCESS) ফিরতে হবে যদি এটি 0 টি উল্লিখিত ফাংশনের সমস্ত ফাইল এবং সমস্ত অনুরোধগুলি খুলতে সক্ষম হয়, অন্যথায় 1 (বা EXIT_FAILURE)। এই জাতীয় ফাংশন থাকা ইউনিক্স-স্টাইলের 'ফিল্টার' প্রোগ্রামগুলি লেখার সহজ করে যা কমান্ড লাইনে বা স্ট্যান্ডার্ড ইনপুটটিতে নির্দিষ্ট করা ফাইলগুলি পড়ে।


আমি পছন্দ করি না যে getopt () প্রথম ফাইলের পরে বিকল্পগুলির অনুমতি দেয় না।
জেক 19

পসিক্স getopt()না; জিএনইউ getopt()ডিফল্টরূপে করে। তোমারটা নাও. ফাইল নামের আচরণের পরে আমি বিকল্পগুলির বিষয়ে আগ্রহী নই, মূলত এটি প্ল্যাটফর্মের মধ্যে নির্ভরযোগ্য নয়।
জোনাথন লেফলার

14

আমি গেজেপটকে বেশ দরকারী বলে খুঁজে পেয়েছি - আপনি একটি সাধারণ কনফিগারেশন ফাইলের সাহায্যে আপনি যে বিকল্পগুলি চান তা সুনির্দিষ্ট করে এবং এটি একটি .c / .h জুড়ি উত্পন্ন করে যা আপনার অ্যাপ্লিকেশনটির সাথে সহজভাবে অন্তর্ভুক্ত হয় এবং লিঙ্ক করে। উত্পন্ন কোডটি getopt_long ব্যবহার করে, বেশিরভাগ সাধারণ কমান্ড লাইনের প্যারামিটারগুলি পরিচালনা করে এবং এটি অনেক সময় সাশ্রয় করতে পারে।

একটি জেনজেপট ইনপুট ফাইলটি এর মতো দেখতে পারে:

version "0.1"
package "myApp"
purpose "Does something useful."

# Options
option "filename" f "Input filename" string required
option "verbose" v "Increase program verbosity" flag off
option "id" i "Data ID" int required
option "value" r "Data value" multiple(1-) int optional 

কোড তৈরি করা সহজ এবং থুতু ছড়িয়ে পড়ে cmdline.hএবং cmdline.c:

$ gengetopt --input=myApp.cmdline --include-getopt

উত্পন্ন কোড সহজেই সংহত করা হয়:

#include <stdio.h>
#include "cmdline.h"

int main(int argc, char ** argv) {
  struct gengetopt_args_info ai;
  if (cmdline_parser(argc, argv, &ai) != 0) {
    exit(1);
  }
  printf("ai.filename_arg: %s\n", ai.filename_arg);
  printf("ai.verbose_flag: %d\n", ai.verbose_flag);
  printf("ai.id_arg: %d\n", ai.id_arg);
  int i;
  for (i = 0; i < ai.value_given; ++i) {
    printf("ai.value_arg[%d]: %d\n", i, ai.value_arg[i]);
  }
}

আপনার যদি কোনও অতিরিক্ত চেকিং করতে হয় (যেমন পতাকাগুলি পারস্পরিক একচেটিয়াভাবে নিশ্চিত করা), আপনি gengetopt_args_infoস্ট্রাক্টে সঞ্চিত ডেটা দিয়ে এটি মোটামুটি সহজেই করতে পারেন ।


1 ++ ব্যতীত এটি এমন কোড উত্পন্ন করে যা সতর্কবার্তা উত্পন্ন করে :(
বিড়াল

হ্যাঁ দুর্ভাগ্যবশত. আমি আমার ক্যামেক ফাইলটিতে ব্যতিক্রম রেখেছি।
ডেভিডা

আমি সম্ভবত এই ফাইলটির সতর্কতাগুলি উপেক্ষা করার জন্য কেবল জিসিসি প্রগমাস ব্যবহার করব (ভয়ঙ্কর আমি জানি)
বিড়াল

মনে রাখবেন যে আপনি উত্সটি পুনরায় জেনারেট করলে আপনি অবশ্যই তাদের হারাবেন, যাতে আপনি এগুলি আপনার বিল্ড প্রক্রিয়ায় একটি প্যাচ হিসাবে প্রয়োগ করতে চাইতে পারেন। সত্যিই আমি নির্দিষ্ট ফাইলগুলিতে সতর্কতা বন্ধ করা আরও সহজ মনে করেছি।
ডেভিডা

ঠিক আছে না, আমি বোঝাতে চাইছি উত্সাহিত #includeফাইলের মধ্যে নয়, চারপাশে প্রগমাস স্থাপন করা। আমার কাছে সতর্কবাণী বন্ধ করা ভার্চুয়াল :-)
বিড়াল

6

আমি খুব আশ্চর্য হয়েছি কেউ জেমস থেলারের "অপ্ট" প্যাকেজটি সামনে আনেনি।

আপনি http://public.lanl.gov/jt/Software/ এ অপ্ট খুঁজে পেতে পারেন

এবং অন্যান্য পদ্ধতির তুলনায় এটি এত সহজ কীভাবে কিছু উদাহরণ সহ একটি চাটুকার পোস্ট এখানে:

http://www.decompile.com/not_invented_here/opt/


4
@ কেট আপনাকে কী মনে করে এর পর থেকে এটির আপডেট দরকার? এটি কেবল সফ্টওয়্যার সম্পর্কে ভুল ধারণা।
জোশুয়া হেজেস

@ জোশুয়াহেজগুলি আমি নিজে প্রকল্পটি বজায় রাখতে না চাইলে আমি আমার সক্রিয়ভাবে রক্ষণাবেক্ষণ কোডটিতে সক্রিয়ভাবে রক্ষণাবেক্ষণ কোডটি ব্যবহার করতে চাই। ২০০ from সালের প্রচুর প্রকল্পগুলি সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয়েছে, তবে এইটি মারা গিয়েছিল এবং সম্ভবত বাগগুলি পড়েছিল Also এছাড়াও, 2 বছর আগে (প্রায় ঠিক!) আমি অনেক আগে লিখেছিলাম যে: পি
বিট

4
অপ্ট সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয় না কারণ এটি সম্পূর্ণ এবং কমপ্যাক্ট। কিক্সের জন্য আমি কেবল এটি ডাউনলোড করে এটিকে তৈরি করার চেষ্টা করেছি (জিসিসি -7.3) এবং পাওয়া গেছে যে গ্রন্থাগারটি তৈরি করে এবং কাজ করে, তবে সি ++ পরীক্ষা কিছু ছোটখাটো কাজ করতে পারে। iostream.h টি আইস্ট্রিম হওয়া উচিত, এবং নেমস্পেস স্ট্যান্ড ব্যবহার করে; যোগ করা উচিত। আমি এটি জেমসকে উল্লেখ করব। এটি কেবল কোডটি নয়, কেবল সি ++ এপিআই পরীক্ষাকে প্রভাবিত করে।
মার্কগ্যালাসি

5

ডকপটের একটি সি বাস্তবায়ন রয়েছে যা আমি ভেবেছিলাম বেশ সুন্দর ছিল: https://github.com/docopt/docopt.c

কমান্ড লাইন অপশনগুলি বর্ণনা করে একটি ম্যান-পৃষ্ঠার মানকযুক্ত বিন্যাস থেকে ডকপ্ট অনুমান করে এবং একটি যুক্তি পার্সার তৈরি করে। অজগর থেকে এটি শুরু হয়েছিল; পাইথন সংস্করণটি আক্ষরিকভাবে কেবলমাত্র ডাস্টস্ট্রিংকে বিশ্লেষণ করে একটি ডিক দেয়। সি তে এটি করতে আরও কিছু কাজ লাগে, তবে এটি ব্যবহার করা পরিষ্কার এবং এর কোনও বাহ্যিক নির্ভরতা নেই।


3

একটি দুর্দান্ত সাধারণ উদ্দেশ্য সি লাইব্রেরি libUCW এর মধ্যে ঝরঝরে কমান্ড-লাইন বিকল্প পার্সিং এবং কনফিগার ফাইল লোডিং অন্তর্ভুক্ত রয়েছে

লাইব্রেরিতে ভাল ডকুমেন্টেশনও আসে এবং কিছু অন্যান্য দরকারী স্টাফ অন্তর্ভুক্ত করে (দ্রুত আইও, ডেটা স্ট্রাকচার, বরাদ্দকারী, ...) তবে এটি আলাদাভাবে ব্যবহার করা যায়।

LibUCW বিকল্প পার্সার উদাহরণ (গ্রন্থাগার ডক্স থেকে)

#include <ucw/lib.h>
#include <ucw/opt.h>

int english;
int sugar;
int verbose;
char *tea_name;

static struct opt_section options = {
  OPT_ITEMS {
    OPT_HELP("A simple tea boiling console."),
    OPT_HELP("Usage: teapot [options] name-of-the-tea"),
    OPT_HELP(""),
    OPT_HELP("Options:"),
    OPT_HELP_OPTION,
    OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
    OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
    OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
    OPT_STRING(OPT_POSITIONAL(1), NULL, tea_name, OPT_REQUIRED, ""),
    OPT_END
  }
};

int main(int argc, char **argv)
{
  opt_parse(&options, argv+1);
  return 0;
}

অবস্থানগত বিকল্পে বাগ রয়েছে। যদি দুটি OPT_STRING থাকে, এবং একটি অবস্থানগত হয় তবে একটি নয়, এটি বিশ্লেষণ করতে পারে না।
নিউবি

2

আমি একটি ছোট্ট লাইব্রেরি লিখেছি যা পিওপেটের মতো আর্গুমেন্টকে পার্স করে, যার সাথে আমার বেশ কয়েকটি সমস্যা ছিল, যার নাম ছিল এক্সঅপ্ট । GNU- স্টাইলের যুক্তি পার্সিং ব্যবহার করে এবং POpt এর সাথে খুব মিল খুঁজে পাওয়া যায়।

আমি এটি সময়ে সময়ে দুর্দান্ত সাফল্যের সাথে ব্যবহার করি এবং এটি যে কোনও জায়গায় কার্যকর হয়।


1

আমার শিংটি টুটিং করা যদি আমি করতে পারি তবে আমি লিখতে পারি যে একটি বিকল্প পার্সিং লাইব্রেরি: ড্রপ

  • এটি একটি সি লাইব্রেরি (চাইলে সি ++ র‌্যাপার সহ)।
  • এটি হালকা ওজনের
  • এটি এক্সটেনসেবল (কাস্টম আর্গুমেন্ট প্রকারগুলি সহজেই যুক্ত করা যায় এবং বিল্ট-ইন আর্গুমেন্টের ধরণের সাথে সমান পাদদেশ থাকতে পারে)।
  • এটি কোনও বহনযোগ্য (সি স্ট্যান্ডার্ড লাইব্রেরি ব্যতীত) কোনও নির্ভরযোগ্যতা ছাড়াই (এটি স্ট্যান্ডার্ড সিতে লিখিত) হওয়া উচিত।
  • এটির একটি খুব বাধাহীন লাইসেন্স রয়েছে (zlib / libpng)।

একটি বৈশিষ্ট্য যা এটির প্রস্তাব দেয় যে অন্য অনেকগুলি পূর্বের বিকল্পগুলিকে ওভাররাইড করার ক্ষমতা রাখে না। উদাহরণস্বরূপ, যদি আপনার শেল ওরফে থাকে:

alias bar="foo --flag1 --flag2 --flag3"

এবং আপনি অক্ষমদের barসাথে ব্যবহার করতে চান তবে --flag1এটি আপনাকে তা করতে দেয়:

bar --flag1=0

0
#include <stdio.h>

int main(int argc, char **argv)
{
    size_t i;
    size_t filename_i = -1;

    for (i = 0; i < argc; i++)
    {
        char const *option =  argv[i];
        if (option[0] == '-')
        {
            printf("I am a flagged option");
            switch (option[1])
            {
                case 'a':
                    /*someting*/
                    break;
                case 'b':
                    break;
                case '-':
                    /* "--" -- the next argument will be a file.*/
                    filename_i = i;
                    i = i + 1;
                    break;
                default:
                    printf("flag not recognised %s", option);
                    break;
            }
        }
        else
        {   
            printf("I am a positional argument");
        }

        /* At this point, if -- was specified, then filename_i contains the index
         into argv that contains the filename. If -- was not specified, then filename_i will be -1*/
     }
  return 0;
}

4
না; এটি করার একদম ভাল উপায় নয় ... যুক্তি পার্সিং ফাংশনগুলির মধ্যে একটি ব্যবহার করুন - getopt()বা getopt_long()
জোনাথন লেফলার

5
প্রতারণার মতো শোনায়, এটি স্পষ্টতই হোমওয়ার্কের প্রশ্ন। অতিরিক্তভাবে, ওপি স্ট্রিং কী এবং এর কিছু অংশ কীভাবে পড়তে হয় সে সম্পর্কে ধারণাটি বুঝতে খুব কঠিন সময় পার হচ্ছে। তার উপর গিওপ্টগুলি ফয়েস্ট করা একটি ভুল।
পড

এটি একটি হোমওয়ার্ক প্রশ্ন। আমি জানি স্ট্রিং কী। কমান্ড লাইন আর্গুমেন্টগুলি কীভাবে ভেঙে ফেলতে হয় তা আমি ঠিক বুঝতে পারি না কারণ আপনি যখন বেশিরভাগ সংখ্যক বিকল্পগুলি ইনপুট করতে পারেন তখন তা আমার কাছে বিভ্রান্তিকর বলে মনে হয়, তাই আপনি ফাইলের নামগুলি কোথায় তা সত্যই বুঝতে পারবেন না। আমি কি ওভারথিংক করছি?
ব্যবহারকারী 1251020

0

সিতে কমান্ড লাইন আর্গুমেন্ট পার্স করার জন্য শিক্ষামূলক টেম্পলেট

সি:> programName -w - fileOne.txt fileTwo.txt

BOOL argLine = FALSE;
BOOL argWord = FALSE;
BOOL argChar = FALSE;
char * fileName1 = NULL;
char * fileName2 = NULL;

int main(int argc, char * argv[]) {
    int i;
    printf("Argument count=%d\n",argc);
    for (i = 0; i < argc; i++) {
        printf("Argument %s\n",argv[i]);
        if (strcmp(argv[i],"-l")==0) {
            argLine = TRUE;
            printf("    argLine=TRUE\n");
        }
        else if (strcmp(argv[i],"-w")==0) {
            argWord = TRUE;
            printf("    argWord=TRUE\n");
        }
        else if (strcmp(argv[i],"-c")==0) {
            argChar = TRUE;
            printf("    argChar=TRUE\n");
        }
        else if (strcmp(argv[i],"--")==0) {
            if (i+1 <= argc) {
                fileName1 = argv[++i];
                printf("    fileName1=%s\n",fileName1);
            }
            if (i+1 <= argc) {
                fileName2 = argv[++i];
                printf("    fileName2=%s\n",fileName2);
            }
        }
    }
    return 0;
}

4
... আমি মনে করি না সিতে বুলিয়ান ভেরিয়েবল আছে ...?
ব্যবহারকারী 1251020

আমার গ্রহ / উইন্ডোজ পরিবেশের টাইপ BOOL রয়েছে। কেবল এটি ইন্ট বা চর টাইপ করুন এবং সেই অনুযায়ী কোড সামঞ্জস্য করুন।
জাভা 42

4
C99 একটি টাইপ হয়েছে _Boolসব সময়ে, এবং একটি হেডার <stdbool.h>যা সংজ্ঞায়িত boolহিসাবে _Boolএবং trueএবং falseএবং __bool_true_false_are_definedসব ম্যাক্রো (যা, অত্যন্ত, অনির্দিষ্ট এবং অনির্ধারিত আচরণ invoking ছাড়া পুনরায় সংজ্ঞায়িত করা যেতে পারে; যে লাইসেন্স, কিন্তু, বাঁধা 'লুপ্তপ্রায়')। সুতরাং, আপনার যদি C99 সংকলক থাকে, আপনি <stdbool.h>এবং ব্যবহার করতে পারেন bool। যদি তা না হয় তবে আপনি নিজের জন্য একটি লিখুন (এটি কঠিন নয়) অথবা আপনি একটি স্থানীয় সমতুল্য ব্যবহার করেন।
জোনাথন লেফলার

4
@ ওলফার মাই সি পরিবেশে টাইপ BOOL রয়েছে (টাইপডেফ ইন্ট BOOL হিসাবে) এবং টাইপ বুলিয়ান (টাইপডেফ স্বাক্ষরবিহীন চর বুলিয়ান হিসাবে) এবং টাইপ বুলের কোনও সংজ্ঞা নেই। উদাহরণস্বরূপ, কেবলমাত্র int বা চর টাইপ করুন এবং সেই অনুযায়ী কোড সামঞ্জস্য করুন।
জাভা 42

4
আমি এই পদ্ধতির সাথে একমত নই। বিকল্পগুলি পার্স করার জন্য একটি লাইব্রেরি ফাংশন ব্যবহার করুন।
জোনাথন লেফলার 15

0
    /*
      Here's a rough one not relying on any libraries.
      Example:
      -wi | -iw //word case insensitive
      -li | -il //line case insensitive
      -- file  //specify the first filename (you could just get the files
      as positional arguments in the else statement instead)
      PS: don't mind the #define's, they're just pasting code :D
    */
    #ifndef OPT_H
    #define OPT_H

    //specify option requires argument
    #define require \
      optarg = opt_pointer + 1; \
      if (*optarg == '\0') \
      { \
        if (++optind == argc) \
          goto opt_err_arg; \
        else \
          optarg = argv[optind]; \
      } \
      opt_pointer = opt_null_terminator;

    //start processing argv
    #define opt \
    int   optind                 = 1; \
    char *opt_pointer            = argv[1]; \
    char *optarg                 = NULL; \
    char  opt_null_terminator[2] = {'\0','\0'}; \
    if (0) \
    { \
      opt_err_arg: \
        fprintf(stderr,"option %c requires argument.\n",*opt_pointer); \
        return 1; \
      opt_err_opt: \
        fprintf(stderr,"option %c is invalid.\n",*opt_pointer); \
        return 1; \
    } \
    for (; optind < argc; opt_pointer = argv[++optind]) \
      if (*opt_pointer++ == '-') \
      { \
        for (;;++opt_pointer) \
          switch (*opt_pointer) \
          {

    //stop processing argv
    #define done \
          default: \
            if (*opt_pointer != '\0') \
              goto opt_err_opt; \
            else \
              goto opt_next; \
            break; \
          } \
        opt_next:; \
      }
    #endif //opt.h

    #include <stdio.h>
    #include "opt.h"
    int
    main (int argc, char **argv)
    {
      #define by_character 0
      #define by_word      1
      #define by_line      2
      int cmp = by_character;
      int case_insensitive = 0;
      opt
      case 'h':
        puts ("HELP!");
        break;
      case 'v':
        puts ("fileCMP Version 1.0");
        break;
      case 'i':
        case_insensitive = 1;
        break;
      case 'w':
        cmp = by_word;
        break;
      case 'l':
        cmp = by_line;
        break;
      case '-':required
        printf("first filename: %s\n", optarg);
        break;
      done
      else printf ("Positional Argument %s\n", argv[optind]);
      return 0;
    }

4
আপনার কোডটি কেবল এটিকে ছুঁড়ে ফেলার পরিবর্তে এবং এটি প্রত্যেকে বুঝতে হবে বলে আশা করার পরিবর্তে আপনাকে ব্যাখ্যা করতে হবে। এটি কেবল অনুলিপি করা এবং আটকানো শেখার জন্য একটি সাইট।
যোকাই

0

ঠিক আছে এটাই দীর্ঘ গল্পের শুরু - তৈরি করা হয়েছে শর্ট 'বোর্ট সি-তে একটি কমান্ড লাইনের বিশ্লেষণ ...

/**
* Helper function to parse the command line
* @param argc Argument Counter
* @param argv Argument Vector
* @param prog Program Instance Reference to fill with options
*/
bool parseCommandLine(int argc, char* argv[], DuplicateFileHardLinker* prog) {
  bool pathAdded = false;

  // iterate over all arguments...
  for ( int i = 1; i<argc; i++ ) {

    // is argv a command line option ?
    if ( argv[i][0] == '-' || argv[i][0] == '/' ) {

// ~~~~~~ Optionally Cut that part vvvvvvvvvvvvv for sake of simplicity ~~~~~~~
      // check for longer options
            if ( stricmp( &argv[i][1], "NoFileName"  ) == 0
              ||  strcmp( &argv[i][1], "q1"          ) == 0 ) {

        boNoFileNameLog = true;
      } else if ( strcmp( &argv[i][1], "HowAreYou?"    ) == 0 ) {
          logInfo( "SECRET FOUND: Well - wow I'm glad ya ask me.");
      } else {

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now here comes the main thing:
//
        // check for one char options
        while ( char option = *++argv[i] ) {

          switch ( option ) {
          case '?':
            // Show program usage

            logInfo(L"Options:");
            logInfo(L"  /q\t>Quite mode");
            logInfo(L"  /v\t>Verbose mode");
            logInfo(L"  /d\t>Debug mode");
            return false;

            // Log options
          case 'q':
            setLogLevel(LOG_ERROR);
            break;

          case 'v':
            setLogLevel(LOG_VERBOSE);
            break;

          case 'd':
            setLogLevel(LOG_DEBUG);
            break;

          default:
            logError(L"'%s' is an illegal command line option!"
                      "  Use /? to see valid options!", option);
            return false;
          } // switch one-char-option
        } //while one-char-options
      }  //else one vs longer options
    } // if isArgAnOption

// 
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^  So that's it! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// What follows now is are some usefull extras...
//
    else {


      // the command line options seems to be a path...
      WCHAR tmpPath[MAX_PATH_LENGTH];
      mbstowcs(tmpPath, argv[i], sizeof(tmpPath));

      // check if the path is existing!
      //...

      prog->addPath(tmpPath); //Comment or remove to get a working example
      pathAdded = true;
    }
  }

  // check for parameters
  if ( !pathAdded ) {
    logError("You need to specify at least one folder to process!\n"
             "Use /? to see valid options!");
    return false;
  }

  return true;
}



int main(int argc, char* argv[]) {

  try {
    // parse the command line
    if ( !parseCommandLine(argc, argv, prog) ) {
      return 1; 
    }

// I know that sample is just to show how the nicely parse commandline Arguments
// So Please excuse more nice useful C-glatter that follows now...
  }
  catch ( LPCWSTR err ) {
    DWORD dwError = GetLastError();
    if ( wcslen(err) > 0 ) {
      if ( dwError != 0 ) {
        logError(dwError, err);
      }
      else {
        logError(err);
      }
    }
    return 2;
  }
}

#define LOG_ERROR               1
#define LOG_INFO                0
#define LOG_VERBOSE             -1
#define LOG_DEBUG               -2

/** Logging Level for the console output */
int logLevel = LOG_INFO;

void logError(LPCWSTR message, ...) {
  va_list argp;
  fwprintf(stderr, L"ERROR: ");
  va_start(argp, message);
  vfwprintf(stderr, message, argp);
  va_end(argp);
  fwprintf(stderr, L"\n");
}


void logInfo(LPCWSTR message, ...) {
  if ( logLevel <= LOG_INFO ) {
    va_list argp;
    va_start(argp, message);
    vwprintf(message, argp);
    va_end(argp);
    wprintf(L"\n");
  }
}

মনে রাখবেন যে এই সংস্করণটি যুক্তি যুক্ত করার পক্ষেও সমর্থন করবে: সুতরাং লেখার পরিবর্তে / h / s -> / hs এছাড়াও কাজ করবে।

এখানে পোস্ট করা এন-তম ব্যক্তি হওয়ার জন্য দুঃখিত - তবে আমি এখানে যে সমস্ত স্ট্যান্ড-একা-সংস্করণ দেখেছি তার সাথে আমি সত্যিই সন্তুষ্ট নই। ভাল কাজগুলি ভাল ছেড়ে যাচ্ছে। তাই আমি পছন্দ হবে libUCW বিকল্প পার্সার, Arg বা Getopt একটি বাড়িতে বানানো বেশী করে।

আপনি পরিবর্তন করতে পারেন নোট:

*++argv[i]-> (++argv*)[0] আরও কম ক্রিপ্টিক তবে এখনও রহস্যজনক।

ঠিক আছে আসুন এটিকে ভেঙে দিন: 1. আরগভি [i] -> আরজিভি-চর পয়েন্টার ক্ষেত্রের আই-তম উপাদানটি অ্যাক্সেস করুন

  1. ++ * ... -> একটি চরের মাধ্যমে আরগভি-পয়েন্টারটি ফরোয়ার্ড করবে

  2. ... [0] -> চরিত্রটি পড়ার পয়েন্টারটি অনুসরণ করবে

  3. ++ (...) -> বন্ধনী রয়েছে তাই আমরা পয়েন্টারটি বাড়িয়ে দেব, চরের মানটি নিজেই করব না।

এত সুন্দর যে সি ##-তে পয়েন্টারগুলি 'মারা গেল' - পয়েন্টারগুলিকে দীর্ঘজীবী করুন !!!

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.