/** * Parse Tokens * Description: Takes a TokenList and a Command object and parses the TokenList in order * to generate a command (list of programs in a pipeline); * Returns: true on success; false otherwise */ bool parseTokens( TokenList tokens, Command * command ) { bool success = true; Program *currentProgram = command->program = newProgram(); bool begin = true; for (int i = 0; i < tokens.count; i++) { char * token = tokens.tokens[i]; // Check if we are at the beginning of a program if ( begin ) { if ( strncmp( token, "time", max( strlen( token ), strlen( "time" ) ) ) == 0 ) { currentProgram->name = token; currentProgram->next = newProgram(); currentProgram = currentProgram->next; begin = true; // If we have at least two tokens left and the next one is a pipe // then make a blank timed program // Note: This doesn't do anything since we don't allow // piped time commands but this would help support it // in the future and it currently prevents better // error checking if ( i + 2 < tokens.count && isPipe( tokens.tokens[i+1] ) ) { currentProgram->name = NULL; currentProgram->next = newProgram(); currentProgram = currentProgram->next; i++; } // The beginning of a program cannot be <, >, &, or | } else if ( !isRedirection( token ) && !isPipe( token ) && !isBackground( token ) ) { currentProgram->name = token; currentProgram->argv[currentProgram->argc++] = token; // Don't come back here again until we process a new program begin = false; } else { error("Program may not start with <, >, |, or &"); success = false; break; } } else { // Process redirection if ( isRedirection( token ) ) { // Only one level of redirection allowed if ( currentProgram->redirect == DEFAULT ) { // Need to have at least one token after a redirect if ( i+1 < tokens.count ) { if ( !isRedirection(tokens.tokens[i+1]) && !isPipe(tokens.tokens[i+1]) && !isBackground(tokens.tokens[i+1]) ) { currentProgram->redirectResource = tokens.tokens[i+1]; currentProgram->redirect = getRedirect( token ); // Skip a token i++; } else { error("Expected file after a redirect"); success = false; break; } } // We can have redirections like <file or >file else if ( strlen( token ) > 1 ) { currentProgram->redirectResource = token+1; currentProgram->redirect = getRedirect( token ); } else { error("Expected file after a redirect"); success = false; break; } } else { error("Only one level of redirection allowed"); success = false; break; } // Process pipe } else if ( isPipe( token ) ) { // Check if there's a token after this one if ( i+1 < tokens.count ) { currentProgram->next = newProgram(); currentProgram = currentProgram->next; begin = true; } else { error("Expected program after pipe"); success = false; break; } // Process background } else if ( isBackground( token ) ) { // & must be last token if ( i+1 >= tokens.count ) command->background = true; else { error("& can only be placed at end of command"); success = false; } break; } // Plain old argument else currentProgram->argv[currentProgram->argc++] = token; } } return success; }
/* Could be a file or a stream. */ void svd_closeFile(FILE *file) { if (file == stdin || file == stdout) return; if (isPipe(file)) pclose(file); else fclose(file); }
void chainNet(char *chainFile, char *tSizes, char *qSizes, char *tNet, char *qNet) /* chainNet - Make alignment nets out of chains. */ { struct lineFile *lf = lineFileOpen(chainFile, TRUE); struct hash *qHash, *tHash; struct chrom *qChromList, *tChromList, *tChrom, *qChrom; struct chain *chain; double lastScore = -1; struct lm *lm = lmInit(0); struct rbTreeNode **rbStack; FILE *tNetFile = mustOpen(tNet, "w"); FILE *qNetFile = mustOpen(qNet, "w"); lmAllocArray(lm, rbStack, 256); makeChroms(qSizes, lm, rbStack, &qHash, &qChromList); makeChroms(tSizes, lm, rbStack, &tHash, &tChromList); verbose(1, "Got %d chroms in %s, %d in %s\n", slCount(tChromList), tSizes, slCount(qChromList), qSizes); lineFileSetMetaDataOutput(lf, tNetFile); lineFileSetMetaDataOutput(lf, qNetFile); /* Loop through chain file building up net. */ while ((chain = chainRead(lf)) != NULL) { /* Make sure that input is really sorted. */ if (lastScore >= 0 && chain->score > lastScore) errAbort("%s must be sorted in order of score", chainFile); lastScore = chain->score; if (chain->score < minScore) { break; } verbose(2, "chain %f (%d els) %s %d-%d %c %s %d-%d\n", chain->score, slCount(chain->blockList), chain->tName, chain->tStart, chain->tEnd, chain->qStrand, chain->qName, chain->qStart, chain->qEnd); qChrom = hashMustFindVal(qHash, chain->qName); if (qChrom->size != chain->qSize) errAbort("%s is %d in %s but %d in %s", chain->qName, chain->qSize, chainFile, qChrom->size, qSizes); tChrom = hashMustFindVal(tHash, chain->tName); if (tChrom->size != chain->tSize) errAbort("%s is %d in %s but %d in %s", chain->tName, chain->tSize, chainFile, tChrom->size, tSizes); if (!inclQuery(chain)) verbose(2, "skipping chain on query %s\n", chain->qName); else { addChain(qChrom, tChrom, chain); verbose(2, "%s has %d inserts, %s has %d\n", tChrom->name, tChrom->spaces->n, qChrom->name, qChrom->spaces->n); } } /* Build up other side of fills. It's just for historical * reasons this is not done during the main build up. * It's a little less efficient this way, but to change it * some hard reverse strand issues would have to be juggled. */ verbose(1, "Finishing nets\n"); finishNet(qChromList, TRUE); finishNet(tChromList, FALSE); /* Write out basic net files. */ verbose(1, "writing %s\n", tNet); outputNetSide(tChromList, tNetFile, FALSE); verbose(1, "writing %s\n", qNet); outputNetSide(qChromList, qNetFile, TRUE); /* prevent SIGPIPE in preceding process if input is a pipe, consume remainder * of input file since we stop before EOF. */ if (isPipe(lf->fd)) { char *line; while(lineFileNext(lf, &line, NULL)) continue; } lineFileClose(&lf); if (verboseLevel() > 1) printMem(stderr); }