Майкл Джонсон - Разработка приложений в среде Linux. Второе издание
104: i = 0;
105: }
106:
107: rc = glob(prog->argv[argc - 1], flags, NULL, &prog->globResult);
108: if (rc == GLOB_NOSPACE) {
109: fprintf(stderr, "недостаточно пространства для универсализацииn");
110: return;
111: } else if (rc == GLOB_NOMATCH ||
112: (!rc && (prog->globResult.gl_pathc - i) == 1 &&
113: !strcmp(prog->argv[argc - 1],
114: prog->globResult.gl_pathv[i]))) {
115: /* нам нужно удалить все, что до сих пор было заключено между */
116: src = dst = prog->argv[argc - 1];
117: while (*src) {
118: if (*src != '\') *dst++ = *src;
119: src++;
120: }
121: *dst = ' ';
122: } else if (!rc) {
123: argcAlloced += (prog->globResult.gl_pathc - i);
124: prog->argv = realloc(prog->argv,
125: argcAlloced * sizeof(*prog->argv));
126: memcpy(prog->argv + (argc - 1),
127: prog->globResult.gl_pathv + i,
128: sizeof(*(prog->argv)) *
129: (prog->globResult.gl_pathc - i));
130: argc += (prog->globResult.gl_pathc - i - 1);
131: }
132:
133: *argcAllocedPtr = argcAlloced;
134: *argcPtr = argc;
135: }
136:
137: /* Возвращаем cmd->numProgs как 0, если не представлено ни одной команды
138: (например, пустая строка). Если будет обнаружена допустимая команда,
139: commandPtr будет ссылаться на начало следующей команды (если исходная
140: команда была связана с несколькими заданиями) или будет равно NULL,
141: если больше не представлено ни одной команды. */
142: int parseCommand(char ** commandPtr, struct job * job, int * isBg) {
143: char * command;
144: char * returnCommand = NULL;
145: char * src, * buf, * chptr;
146: int argc = 0;
147: int done = 0;
148: int argvAlloced;
149: int i;
150: char quote = ' ';
151: int count;
152: struct childProgram * prog;
153:
154: /* пропускаем первое свободное место (например, пробел) */
155: while (**commandPtr && isspace(**commandPtr)) (*commandPtr)++;
156:
157: /* обрабатываем пустые строки и первые символы '#' */
158: if (!**commandPtr || (**commandPtr=='#')) {
159: job->numProgs = 0;
160: *commandPtr = NULL;
161: return 0;
162: }
163:
164: *isBg = 0;
165: job->numProgs = 1;
166: job->progs = malloc(sizeof(*job->progs));
167:
168: /* Мы задаем элементы массива argv для ссылки внутри строки.
169: Освобождение памяти осуществляется с помощью функции freeJob().
170:
171: Получив незанятую память, нам не нужно будет использовать завершающие
172: значения NULL, поэтому оставшаяся часть будет выглядеть аккуратнее
173: (хотя, честно говоря, менее эффективно). */
174: job->cmdBuf = command = calloc(1, strlen(*commandPtr) + 1);
175: job->text = NULL;
176:
177: prog = job->progs;
178: prog->numRedirections = 0;
179: prog->redirections = NULL;
180: prog->freeGlob = 0;
181: prog->isStopped = 0;
182:
183: argvAlloced = 5;
184: prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
185: prog->argv[0] = job->cmdBuf;
186:
187: buf = command;
188: src = *commandPtr;
189: while (*src && !done) {
190: if (quote == *src) {
191: quote = ' ';
192: } else if (quote) {
193: if (*src ==0 '\') {
194: src++;
195: if (!*src) {
196: fprintf(stderr,
197: "после \ ожидался символn");
198: freeJob(job);
199: return 1;
200: }
201:
202: /* в оболочке сочетание "'" должно дать */
203: if (*src != quote) *buf++ = '\';
204: } else if (*src == '*' | | *src == ' ?' | | *src == '[' ||
205: *src == ']')
206: *buf++ = '\';
207: *buf++ = *src;
208: } else if (isspace(*src)) {
209: if (*prog->argv[argc]) {
210: buf++, argc++;
211: /* +1 здесь оставляет место для NULL, которое
212: завершает массив argv */
213: if ((argc + 1) == argvAlloced) {
214: argvAlloced += 5;
215: prog->argv = realloc(prog->argv,
216: sizeof(*prog->argv) * argvAlloced);
217: }
218: prog->argv[argc] = buf;
219:
220: globLastArgument(prog, &argc, &argvAlloced);
221: }
222: } else switch (*src) {
223: case '"':
224: case ''':
225: quote = *src;
226: break;
227:
228: case '#': /* комментарий */
229: done = 1;
230: break;
231:
232: case '>': /* переадресации */
233: case '<':
234: i = prog->numRedirections++;
235: prog->redirections = realloc(prog->redirections,
236: sizeof(*prog->redirections) * (i+1));
237:
238: prog->redirections[i].fd= -1;
239: if (buf != prog->argv[argc]) {
240: /* перед этим символом может быть указан номер
241: переадресовываемого файла */
242: prog->redirections[i].fd =
243: strtol(prog->argv[argc], &chptr, 10);
244:
245: if (*chptr && *prog->argv[argc]) {
246: buf++, argc++;
247: globLastArgument(prog, &argc, &argvAlloced);
248: }
249: }
250:
251: if (prog->redirections[i].fd == -1) {
252: if (*src == '>')
253: prog->redirections[i].fd = 1;
254: else
255: prog->redirections[i].fd = 0;
256: }
257:
258: if (*src++ == '>') {
259: if (*src == '>') {
260: prog->redirections[i].type = REDIRECT_APPEND;
261: src++;
262: } else {
263: prog->redirections[i].type = REDIRECT_OVERWRIТЕ;
264: }
265: } else {
266: prog->redirections[i].type = REDIRECT_INPUT;
267: }
268:
269: /* Это не соответствует стандарту sh POSIX. Ну и ладно. */
270: chptr = src;
271: while (isspace(*chptr)) chptr++;
272:
273: if (!*chptr) {
274: fprintf(stderr, "после %c ожидалось имя файлаn",
275: *src);
276: freeJob(job);
277: return 1;
278: }
279:
280: prog->redirections[i].filename = buf;
281: while (*chptr && !isspace(*chptr))
282: *buf++ = *chptr++;
283:
284: src = chptr - 1; /* src++ будет сделано позже */
285: prog->argv[argc] = ++buf;
286: break;
287:
288: case '|': /* канал */
289: /* завершение этой команды */
290: if (*prog->argv[argc]) argc++;
291: if (large) {
292: fprintf(stderr, "пустая команда в каналеn");
293: freeJob(job);
294: return 1;
295: }
296: prog->argv[argc] = NULL;
297:
298: /* и начало следующей */
299: job->numProgs++;
300: job->progs = realloc(job->progs,
301: sizeof (*job->progs) *
302: job->numProgs);
303: prog = job->progs + (job->numProgs - 1);
304: prog->numRedirections = 0;
305: prog->redirections = NULL;
306: prog->freeGlob = 0;
307: argc = 0;
308:
309: argvAlloced = 5;
310: prog->argv = malloc(sizeof(*prog->argv) *
311: argvAlloced);
312: prog->argv[0] = ++buf;
313:
314: src++;
315: while (*src && isspace(*src)) src++;
316:
317: if (!*src) {
318: fprintf(stderr, "пустая команда в каналеn");
319: return 1;
320: }
321: src--; /* инкремент ++ мы сделаем в конце цикла */
322:
323: break;
324:
325: case '&': /* фон */
326: *isBg = 1;
327: case ';': /* разнообразные команды */
328: done = 1;
329: returnCommand = *commandPtr + (src - * commandPtr) + 1;
330: break;
331:
332: case '\':
333: src++;
334: if (!*src) {
335: freeJob(job);
336: fprintf(stderr, "после \ ожидался символn");
337: return 1;
338: }
339: if (*src == '*' | | *src == '[' || *src == '] '
340: || *src == '?')
341: *buf++ = '\';
342: /* неудача */
343: default:
344: *buf++ = *src;
345: }
346:
347: src++;
348: }
349:
350: if (*prog->argv[argc]) {
351: argc++;
352: globLastArgument(prog, &argc, &argvAlloced);
353: }
354: if (!argc) {
355: freeJob(job);
356: return 0;
357: }
358: prog->argv[argc] = NULL;
359:
360: if (!returnCommand) {
361: job->text = malloc(strlen(*commandPtr) + 1);