Выбрать главу

 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:  /* поместить дочернюю программу в отдельную группу процессов */