75: char *src, *buf;
76: int argc = 0;
77: int done = 0;
78: int argvAlloced;
79: char quote = '\0';
80: int count;
81: struct childProgram *prog;
82:
83: /* Пропустить ведущие пробелы */
84: while(**commandPtr && isspace(**commandPtr)) (*commandPtr)++;
85:
86: /* здесь обрабатываются пустые строки и ведущие символы '#' */
87: if (!**commandPtr || (**commandPtr=='#')) {
88: job->numProgs = 0;
89: *commandPtr = NULL;
90: return 0;
91: }
92:
93: *isBg = 0;
94: job->numProgs = 1;
95: job->progs = malloc(sizeof(*job->progs));
96:
97: /* Мы устанавливаем элементы argv в указатели внутри строки.
98: Память освобождается freeJob().
99:
100: Получение чистой памяти позволяет далее иметь дело с
101: NULL-завершающимися вещами и делает все остальное немного
102: яснее (к тому же, это добавляет эффективности) */
103: job->cmdBuf = command = calloc(1, strlen(*commandPtr) + 1);
104: job->text = NULL;
105:
106: prog = job->progs;
107:
108: argvAlloced = 5;
109: prog->argv = malloc(sizeof(*prog->argv) * argvAlloced);
110: prog->argv[0] = job->cmdBuf;
111:
112: buf = command;
113: src = *commandPtr;
114: while (*src && !done) {
115: if (quote==*src) {
116: quote='\0';
117: } else if (quote) {
118: if (*src == '\\') {
119: src++;
120: if (!*src) {
121: fprintf(stderr,
122: "ожидается символ после\\\n");
123: freeJob(job);
124: return 1;
125: }
126:
127: /* в оболочке, "\'" должно породить \' */
128: if (*src != quote) *buf++='\\';
129: }
130: *buf++ = *src;
131: } else if (isspace(*src)) {
132: if (*prog->argv[argc]) {
133: buf++, argc++;
134: /* +1 здесь оставляет место для NULL,
135: которым завершается argv */
136: if ((argc+1) == argvAlloced) {
137: argvAlloced += 5;
138: prog->argv = realloc(prog->argv,
139: sizeof(*prog->argv)*argvAlloced);
140: }
141: prog->argv[argc]=buf;
142: }
143: } else switch(*src) {
144: case '"':
145: case '\'':
146: quote = *src;
147: break;
148:
149: case '#' : /* комментарий */
150: done=1;
151: break;
152:
153: case '&': /* фоновый режим */
154: *isBg = 1;
155: case ';': /* множественные команды */
156: done=1;
157: return Command = *commandPtr + (src - *commandPtr) + 1;
158: break;
159:
160: case '\\' :
161: src++;
162: if (!*src) {
163: freeJob(job);
164: fprintf(stderr, "ожидается символ после \\\n");
165: return 1;
166: }
167: /* двигаться дальше */
168: default:
169: *buf++=*src;
170: }
171:
172: src++;
173: }
174:
175: if (*prog->argv[argc]) {
176: argc++;
177: }
178: if (!argc) {
179: freeJob(job);
180: return 0;
181: }
182: prog->argv[argc]=NULL;
183:
184: if (!returnCommand) {
185: job->text = malloc(strlen(*commandPtr) + 1);
186: strcpy(job->text,*commandPtr);
187: } else {
188: /* Это оставляет хвостовые пробелы, что несколько излишне */
189:
190: count = returnCommand - *commandPtr;
191: job->text = malloc(count + 1);
192: strncpy(job->text,*commandPtr,count);
193: job->text[count] = '\0';
194: }
195:
196: *commandPtr = returnCommand;
197:
198: return 0;
199: }
200:
201: int runCommand(struct jobnewJob, struct jobSet *jobList,
202: intinBg) {
203: struct job *job;
204:
205: /* обходной путь "вручную" - мы не используем fork(),
206: поэтому не можем легко реализовать фоновый режим */
207: if (!strcmp(newJob.progs[0].argv[0], "exit")) {
208: /* это должно вернуть реальный код возврата */
209: exit(0);
210: } else if(!strcmp(newJob.progs[0].argv[0], "jobs")) {
211: for (job = jobList->head; job; job = job->next)
212: printf(JOB_STATUS_FORMAT, job->jobId, "Работаю",
213: job->text);
214: return 0;
215: }
216:
217: /* у нас пока только одна программа на дочернее задание,
218: потому это просто */
219: if (!(newJob.progs[0].pid = fork())) {
220: execvp(newJob.progs[0].argv[0],newJob.progs[0].argv);
221: fprintf(stderr, "exec() для %s потерпела неудачу: %s\n",
222: newJob.progs[0].argv[0],
223: strerror(errno));
224: exit(1);
225: }
226:
227: /* поместить дочернюю программу в отдельную группу процессов */