getopt_long_only возвращает -1 при втором вызове - PullRequest
0 голосов
/ 19 июня 2020

Я писал преобразование C ++ в tcl для c pro, принимающего аргументы. Он использует getop_long_only. Мне удалось загрузить созданную общую библиотеку и запустить ее в первый раз. Однако во второй раз, когда я звоню, getop_long_only всегда дает мне -1, и это вызывает сбой в работе pro c. Снимок звонка ниже. Я также включаю раздел кода. Не могли бы вы объяснить, что происходит?

******************** ЗВОНИТЕ ************** **************

enter code here
$ tclsh
% load area.so area
% area --area --length 4.0 --breadth 4.0
OPT ==> 97
OPT ==> 108
OPT ==> 98
OPT ==> -1
Area0: 1
Perimeter0: 0
Length0: 4
Breadth0: 4

Area: 16
Area: 16
Perimeter: 0

% area --area --length 4.0 --breadth 5.0
OPT ==> -1
rea0: 0
Perimeter0: 0
Length0: -1
Breadth0: -1

-area:           Return the area
-perimeter:      Return the perimeter
-length <val>:   Specify the length
-breadth <val>:  Specify the width
-help:           Show help
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <iostream>
#include <tcl.h>

//  Program to calculate the area and perimeter of 
//  a rectangle using command line arguments
//----------------------------------------------------
void PrintHelp() {
   std::cout <<
        "-area:           Return the area\n"
        "-perimeter:      Return the perimeter\n"
        "-length <val>:   Specify the length\n"
        "-breadth <val>:  Specify the width\n"
        "-help:           Show help\n";
   exit(1);
}


//  area --
//  This implements the random Tcl command. With no arguments
//  the command returns a random integer.
//  With an integer valued argument "range",
//  it returns a random integer between 0 and range.
//--------------------------------------------------------------
extern "C" int AreaCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char **argv) {
   int opt= 0;
   int area = 0, perimeter = 0, breadth = -1, length =-1;

   while (1) {

  //Specifying the expected options
  //The two options l and b expect numbers as argument
     static struct option long_options[] = {
        {"area",      no_argument,       0,  'a' },
        {"perimeter", no_argument,       0,  'p' },
        {"length",    required_argument, 0,  'l' },
        {"breadth",   required_argument, 0,  'b' },
        {"help",      no_argument,       0,  'h' },
        {0,           0,                 0,  0   }
     };

     int long_index =0;
     char* const* new_argv = const_cast<char * const *>(argv);
     opt = getopt_long_only(argc, new_argv,"", long_options, &long_index );

     printf("OPT ==> %d\n",opt);

     if (opt == -1) {
        break;
     }

     switch (opt) {
        case 'a' : area = 1;
        break;
        case 'p' : perimeter = 1;
        break;
        case 'l' : length = atoi(optarg);
        break;
        case 'b' : breadth = atoi(optarg);
        break;
        case 'h': // -h or --help
        case '?': // Unrecognized option
        default: PrintHelp();
        exit(EXIT_FAILURE);
     }
  }

  printf("Area0: %d\n",area);
  printf("Perimeter0: %d\n",perimeter);
  printf("Length0: %d\n",length);
  printf("Breadth0: %d\n\n",breadth);

  if (length == -1 || breadth ==-1) {
     PrintHelp();
     exit(EXIT_FAILURE);
  }
  // Calculate the area
  if (area == 1) {
     area = length * breadth;
     printf("Area: %d\n",area);
  }

  // Calculate the perimeter
  if (perimeter == 1) {
     perimeter = 2 * (length + breadth);
     printf("Perimeter: %d\n",perimeter);
  }

  //char* result;
  //sprintf(result,"%d",rand);
  //Tcl_SetResult(interp, result, TCL_VOLATILE);

  printf("Area: %d\n",area);
  printf("Perimeter: %d\n",perimeter);

  return TCL_OK;

 }

1 Ответ

1 голос
/ 19 июня 2020

Если мы посмотрим на документацию для getopt_long_only(), мы увидим следующие ключевые строки:

Переменная optind - это индекс следующего элемент для обработки в argv . Система инициализирует это значение равным 1. Вызывающий может сбросить его до 1, чтобы перезапустить сканирование того же argv или при сканировании нового вектора аргументов.

А также:

Примечания

Программа, которая сканирует несколько векторов аргументов или повторно сканирует один и тот же вектор более одного раза, и хочет использовать расширения GNU, такие как '+' и '-' в начало optstring или изменение значения POSIXLY_CORRECT между сканированиями, необходимо повторно инициализировать getopt(), сбросив optind на 0, а не на традиционное значение 1 . (Сброс в 0 приводит к вызову внутренней процедуры инициализации, которая повторно проверяет POSIXLY_CORRECT и проверяет наличие расширений GNU в optstring .)

Ваш код не reset optind перед синтаксическим анализом нового набора аргументов (обычно это не упоминается для getopt() и друзей, поскольку их обычный случай предназначен для одноразового синтаксического анализа аргументов командной строки). Вы должны изменить это для этого случая. Если вы собираетесь использовать расширение из нескольких потоков, вам следует переключиться на другое решение для синтаксического анализа, которое больше использует встроенные функции Tcl; у них нет общего состояния между потоками.

...