/* * Search for a line which contains the specified string. * If the string is "", then the previously searched for string * is used. The currently searched for string is saved for future use. * Returns the line number which matches, or 0 if there was no match * with an error printed. */ static NOINLINE int searchLines(const char *str, int num1, int num2) { const LINE *lp; int len; if (bad_nums(num1, num2, "search")) return 0; if (*str == '\0') { if (searchString[0] == '\0') { bb_error_msg("no previous search string"); return 0; } str = searchString; } if (str != searchString) strcpy(searchString, str); len = strlen(str); lp = findLine(num1); if (lp == NULL) return 0; while (num1 <= num2) { if (findString(lp, str, len, 0) >= 0) return num1; num1++; lp = lp->next; } bb_error_msg("can't find string \"%s\"", str); return 0; }
/* * Print lines in a specified range. * The last line printed becomes the current line. * If expandFlag is TRUE, then the line is printed specially to * show magic characters. */ static int printLines(int num1, int num2, int expandFlag) { const LINE *lp; const char *cp; int ch, count; if (bad_nums(num1, num2, "print")) return FALSE; lp = findLine(num1); if (lp == NULL) return FALSE; while (num1 <= num2) { if (!expandFlag) { write(1, lp->data, lp->len); setCurNum(num1++); lp = lp->next; continue; } /* * Show control characters and characters with the * high bit set specially. */ cp = lp->data; count = lp->len; if ((count > 0) && (cp[count - 1] == '\n')) count--; while (count-- > 0) { ch = *cp++; if (ch & 0x80) { fputs("M-", stdout); ch &= 0x7f; } if (ch < ' ') { bb_putchar('^'); ch += '@'; } if (ch == 0x7f) { bb_putchar('^'); ch = '?'; } bb_putchar(ch); } fputs("$\n", stdout); setCurNum(num1++); lp = lp->next; } return TRUE; }
/* * Write the specified lines out to the specified file. * Returns TRUE if successful, or FALSE on an error with a message output. */ static int writeLines(const char *file, int num1, int num2) { LINE *lp; int fd, lineCount, charCount; if (bad_nums(num1, num2, "write")) return FALSE; lineCount = 0; charCount = 0; fd = creat(file, 0666); if (fd < 0) { bb_simple_perror_msg(file); return FALSE; } printf("\"%s\", ", file); fflush_all(); lp = findLine(num1); if (lp == NULL) { close(fd); return FALSE; } while (num1++ <= num2) { if (full_write(fd, lp->data, lp->len) != lp->len) { bb_simple_perror_msg(file); close(fd); return FALSE; } charCount += lp->len; lineCount++; lp = lp->next; } if (close(fd) < 0) { bb_simple_perror_msg(file); return FALSE; } printf("%d lines, %d chars\n", lineCount, charCount); return TRUE; }
/* * Print lines in a specified range. * The last line printed becomes the current line. * If expandFlag is TRUE, then the line is printed specially to * show magic characters. */ static int printLines(int num1, int num2, int expandFlag) { const LINE *lp; const char *cp; int ch, count; if (bad_nums(num1, num2, "print")) return FALSE; lp = findLine(num1); if (lp == NULL) return FALSE; while (num1 <= num2) { if (!expandFlag) { write(STDOUT_FILENO, lp->data, lp->len); setCurNum(num1++); lp = lp->next; continue; } /* * Show control characters and characters with the * high bit set specially. */ cp = lp->data; count = lp->len; if ((count > 0) && (cp[count - 1] == '\n')) count--; while (count-- > 0) { ch = (unsigned char) *cp++; fputc_printable(ch | PRINTABLE_META, stdout); } fputs("$\n", stdout); setCurNum(num1++); lp = lp->next; } return TRUE; }
/* * Delete lines from the given range. */ static void deleteLines(int num1, int num2) { LINE *lp, *nlp, *plp; int count; if (bad_nums(num1, num2, "delete")) return; lp = findLine(num1); if (lp == NULL) return; if ((curNum >= num1) && (curNum <= num2)) { if (num2 < lastNum) setCurNum(num2 + 1); else if (num1 > 1) setCurNum(num1 - 1); else curNum = 0; } count = num2 - num1 + 1; if (curNum > num2) curNum -= count; lastNum -= count; while (count-- > 0) { nlp = lp->next; plp = lp->prev; plp->next = nlp; nlp->prev = plp; free(lp); lp = nlp; } dirty = TRUE; }
/* * Do the substitute command. * The current line is set to the last substitution done. */ static void subCommand(const char *cmd, int num1, int num2) { char *cp, *oldStr, *newStr, buf[USERSIZE]; int delim, oldLen, newLen, deltaLen, offset; LINE *lp, *nlp; int globalFlag, printFlag, didSub, needPrint; if (bad_nums(num1, num2, "substitute")) return; globalFlag = FALSE; printFlag = FALSE; didSub = FALSE; needPrint = FALSE; /* * Copy the command so we can modify it. */ strcpy(buf, cmd); cp = buf; if (isblank(*cp) || (*cp == '\0')) { bb_error_msg("bad delimiter for substitute"); return; } delim = *cp++; oldStr = cp; cp = strchr(cp, delim); if (cp == NULL) { bb_error_msg("missing 2nd delimiter for substitute"); return; } *cp++ = '\0'; newStr = cp; cp = strchr(cp, delim); if (cp) *cp++ = '\0'; else cp = (char*)""; while (*cp) switch (*cp++) { case 'g': globalFlag = TRUE; break; case 'p': printFlag = TRUE; break; default: bb_error_msg("unknown option for substitute"); return; } if (*oldStr == '\0') { if (searchString[0] == '\0') { bb_error_msg("no previous search string"); return; } oldStr = searchString; } if (oldStr != searchString) strcpy(searchString, oldStr); lp = findLine(num1); if (lp == NULL) return; oldLen = strlen(oldStr); newLen = strlen(newStr); deltaLen = newLen - oldLen; offset = 0; nlp = NULL; while (num1 <= num2) { offset = findString(lp, oldStr, oldLen, offset); if (offset < 0) { if (needPrint) { printLines(num1, num1, FALSE); needPrint = FALSE; } offset = 0; lp = lp->next; num1++; continue; } needPrint = printFlag; didSub = TRUE; dirty = TRUE; /* * If the replacement string is the same size or shorter * than the old string, then the substitution is easy. */ if (deltaLen <= 0) { memcpy(&lp->data[offset], newStr, newLen); if (deltaLen) { memcpy(&lp->data[offset + newLen], &lp->data[offset + oldLen], lp->len - offset - oldLen); lp->len += deltaLen; } offset += newLen; if (globalFlag) continue; if (needPrint) { printLines(num1, num1, FALSE); needPrint = FALSE; } lp = lp->next; num1++; continue; } /* * The new string is larger, so allocate a new line * structure and use that. Link it in place of * the old line structure. */ nlp = xmalloc(sizeof(LINE) + lp->len + deltaLen); nlp->len = lp->len + deltaLen; memcpy(nlp->data, lp->data, offset); memcpy(&nlp->data[offset], newStr, newLen); memcpy(&nlp->data[offset + newLen], &lp->data[offset + oldLen], lp->len - offset - oldLen); nlp->next = lp->next; nlp->prev = lp->prev; nlp->prev->next = nlp; nlp->next->prev = nlp; if (curLine == lp) curLine = nlp; free(lp); lp = nlp; offset += newLen; if (globalFlag) continue; if (needPrint) { printLines(num1, num1, FALSE); needPrint = FALSE; } lp = lp->next; num1++; } if (!didSub) bb_error_msg("no substitutions found for \"%s\"", oldStr); }