Я пытаюсь tokenize строку для миниатюрных cstrings "&&" и "||". Я использовал strtok_r() для некоторого хорошего успеха, но из-за отсутствия понимания в strtok_r() или, возможно, недоразумения указателей, я не могу заставить анализатор правильно вести себя.
Код
121 char *cstr3;
122 char* sp;
123 int fc = findclosest(cstr2);
124 switch (fc){
125 case 0:
126 std::cout << "that it"; //debug
127 cstr3 = strtok_r(cstr2, ";", &sp);
128 break;
129
130 case 1:
131 std::cout << ";"; //debug
132 cstr3 = strtok_r(cstr2, ";", &sp);
133 break;
134
135 case 2:
136 std::cout << "&&"; //debug
137 cstr3 = strtok_r(cstr2, "&", &sp);
138 break;
139
140 case 3:
141 std::cout << "||"; //debug
142 cstr3 = strtok_r(cstr2, "|", &sp);
143 break;
144
145 default:
146 break;
147 }
148
149 puts(cstr3);//debug
150 while(cstr3 != NULL)
151 {
152 char mustfail =0;
153 char mustpass =0;
154
155 int a = fcall(breakitup(cstr3));
156
157 if (a > 0){
158 delete[] cstr;
159 goto skippy;
160 }
161
162 fc = findclosest(cstr3);
163
164 switch (fc){
165 case 0:
166 cstr3 = strtok_r(NULL, ";", &sp);
167 break;
168
169 case 1:
170 std::cout << ";"; //debug
171 cstr3 = strtok_r(NULL, ";", &sp);
172 break;
173
174 case 2:
175 std::cout << "&&"; //debug
176 cstr3 = strtok_r(NULL, "&", &sp );
177 break;
178
179 case 3:
180 std::cout << "||"; //debug
181 cstr3 = strtok_r(NULL, "|", &sp);
182 break;
183
184 default:
185 break;
186 }
187 if (cstr3 != NULL){ //debug
188 puts(cstr3);
189 }
190 }
Вместо того, чтобы кормить следующую команду без "&" или "|", она подает строку STARTING на одну. Поэтому я предполагаю, что синтаксический анализатор удалил только первый "&",
Для лучшего объяснения выводится следующее (строка начинается с '>' для обозначения ввода). Извинения, некоторые отладочные заявления все еще находятся в результатах.
> pwd; ls
;pwd //debug
/folder/folder/folder/project //function works properly
ls //debug
notrshell README.md rshell.cpp shelly supershell
> pwd && ls
&&pwd //debug
/folder/folder/folder/project
& ls //debug
Из-за этого дополнительного "&" следующая команда интерпретируется неправильно, есть ли простой способ пропустить только этот "&"?
Я попробовал повторить ту же самую команду, например:
176 cstr3 = strtok_r(NULL, "&", &sp );
177 cstr3 = strtok_r(NULL, "&", &sp );
предполагая, что он просто удалит другой &, но это не сработало.
Я также попытался переместить указатель, чтобы скрытно пропустить дополнительный &,
176 cstr3 = 1+ strtok_r(NULL, "&", &sp );
но не только это было абсолютно дрянным, но и это тоже не сработало.
Есть ли что-то, что я могу узнать о strtok_r() или указателях, которые исправят этот беспорядок?
Рассмотрим этот вход: pwd && ls
.
В первом операторе switch
вы делаете:
cstr3 = strtok_r(cstr2, "&", &sp);
После этого вызова cstr3
указывает на строку: "pwd "
, как, в соответствии с руководством:
Каждый вызов strtok() возвращает указатель на строку с нулевым завершением, содержащую следующий токен. В эту строку не входит байт с разделителями.
sp
указывает на... Ну, в руководстве не говорится об этом буквально, но наиболее вероятным является то, где он заканчивается в последнем вызове - в нашем случае, сразу после разделителя, который есть &
. Таким образом, это указывает на часть нашей строки: & ls
. И это то, что подписывается на второй вызов strtok_r
.
Я не могу быть уверен, но я думаю, что есть проблема в функции findclosest
- можете ли вы подтвердить, что она возвращает правильное значение здесь?
Во всяком случае, из руководства:
Аргумент delim указывает набор байтов, которые ограничивают токены в анализируемой строке.
Это означает, что вы должны использовать "&&"
в качестве разделителя. Это должно решить проблему.
Когда вы вызываете системные функции, помните, что для некоторых (наиболее?) Оболочек одиночный &
в конце команды помещает его выполнение в фоновом режиме.
findclosest
возвращает число в зависимости от того, является ли следующий ближайший объект точкой с запятой, парным findclosest
или парным амперсандом. Работает очень надежно, просто лениво. К сожалению, другая функция (breakitup) также использовала strtok, и я предполагаю, что поведение, пересекающее эти два, стало неопределенным. С тех пор я запускаю их отдельно с отличными результатами! Спасибо за вашу помощь!
strtok
и strtok_r
должны относиться к одной и той же строке - если вы используете другую, она испортится.
std::string
иstring::find
иstring::substr
. Строки в стиле C небезопасны, а функцияstrtok()
изменяет строку в стиле C.