/*--------------------------------------------------------------*/ /* binedit.c: binary file editor */ /* */ /* build using "cc -o binedit binedit.c -lcurses -ltermcap" */ /*--------------------------------------------------------------*/ #include #include #include #define BUFSIZE 65536 /*--------------------------------------------------------*/ /* Global variable definitions */ /*--------------------------------------------------------*/ FILE *fi; char *inbuf, *infile; long int filesize, searchptr; int curbufs, mod, length, count; short format, bcol, eol, divf, writeprot; char sstr[256]; /*--------------------------------------------------------*/ /* Find substring inside of inbuf */ /*--------------------------------------------------------*/ long int searchstr() { char *cptr = sstr, *nptr; long int iptr = searchptr + 1; while (iptr <= filesize - length) { nptr = inbuf + iptr; while (*nptr++ == *cptr && cptr != sstr + length) cptr++; if (cptr == sstr + length) return iptr; else { iptr++; cptr = sstr; } } if (iptr >= filesize - length) { iptr = 0; while (iptr <= searchptr) { nptr = inbuf + iptr; while (*nptr++ == *cptr && cptr != sstr + length) cptr++; if (cptr == sstr + length) return iptr; else { iptr++; cptr = sstr; } } if (iptr >= searchptr - length) { beep(); mvprintw(LINES - 1, 0, "Search failed."); length = 0; clrtoeol(); return filesize; } } return iptr; } /*--------------------------------------------------------*/ /* Calculate the number of columns per row */ /*--------------------------------------------------------*/ void calccols() { if (format == 2) { eol = bcol = (short) COLS; divf = 1; } else if (format == 1) { bcol = (short) (COLS / 3); eol = bcol * 3; divf = 3; } else { bcol = (short) (COLS >> 2); eol = bcol << 2; divf = 4; } } /*--------------------------------------------------------*/ /* Get the file position of the cursor */ /*--------------------------------------------------------*/ long int getpos (curx, cury, curpos) short *curx, *cury; long int *curpos; { return *curpos + (*cury * bcol) + (*curx / divf); } /*--------------------------------------------------------*/ /* Get input and replace a single character */ /*--------------------------------------------------------*/ int replace(curx, cury, curpos) short *curx, *cury; long int *curpos; { chtype inkey[3]; char inword[5]; if (format == 2) inkey[0] = getch(); else while(isspace(inkey[0] = getch())); if ((char) inkey[0] == '\033') { refresh(); return 1; } addch(inkey[0]); if (format == 2) { *(inbuf + getpos(curx, cury, curpos)) = (char) inkey[0]; } else { inkey[1] = getch(); if ((char) inkey[1] == '\033') { refresh(); return 1; } addch(inkey[1]); inword[0] = (char) inkey[0]; inword[1] = (char) inkey[1]; if (format == 1) { inword[2] = '\0'; *(inbuf + getpos(curx, cury, curpos)) = (char)((int) strtol(inword, NULL, 16)); } else { inkey[2] = getch(); if ((char) inkey[2] == '\033') { refresh(); return 1; } addch(inkey[2]); inword[2] = (char) inkey[2]; inword[3] = '\0'; *(inbuf + getpos(curx, cury, curpos)) = (char) atoi(inword); } } mod++; return 0; } /*--------------------------------------------------------*/ /* Move to start of nearest character */ /*--------------------------------------------------------*/ movepos(curx, cury) short *curx, *cury; { if (format == 2) return; else if (format == 1) { if (*curx >= eol) *curx -= 3; *curx = ((*curx) / 3) * 3; } else { if (*curx >= eol) *curx -= 4; *curx = ((*curx) >> 2) << 2; } move(*cury, *curx); } /*--------------------------------------------------------*/ /* Response to keyboard input */ /*--------------------------------------------------------*/ short dokeyhandle(keyin, curx, cury, curpos) int keyin; short *curx, *cury; long int *curpos; { FILE *fd; short rfresh = 0; int temp; long int pagend = *curpos + LINES * bcol; /* file position at end-of-page */ char linein[256], tmpval; long int cpos, npos, tmpptr, i; if (isdigit((char)keyin) && !((char)keyin == '0' && count == 0)) { count *= 10; count += (int)((char)keyin - '0'); mvprintw(LINES - 1, 0, "Do times: %d", count); clrtoeol(); } else { switch((char)keyin) { case 'x': if (count == 0) count++; for (cpos = getpos(curx, cury, curpos); cpos < filesize - count; cpos++) *(inbuf + cpos) = *(inbuf + cpos + count); filesize -= count; rfresh = 1; break; case 'i': movepos(curx, cury); tmpval = *(inbuf + getpos(curx, cury, curpos)); while (replace(curx, cury, curpos) == 0){ filesize++; if (filesize >= BUFSIZE * curbufs) { if ((inbuf = (char *) realloc(inbuf, (++curbufs) * BUFSIZE * sizeof(char))) == NULL) { endwin(); printf("Error: Out of memory at %d bytes!\n", BUFSIZE * (curbufs - 1)); exit(0); } } for (cpos = filesize - 2; cpos > getpos(curx, cury, curpos); cpos--) *(inbuf + cpos + 1) = *(inbuf + cpos); *(inbuf + cpos + 1) = tmpval; printscr(curpos); (*curx) += divf; movepos(curx, cury); } rfresh = 1; break; case 'r': temp = count; count = 0; do { movepos(curx, cury); if (replace(curx, cury, curpos) == 1) temp = 0; if (temp) dokeyhandle('l', curx, cury, curpos); } while (--temp > 0); break; case 'R': movepos(curx, cury); while (replace(curx, cury, curpos) == 0){ (*curx) += divf; movepos(curx, cury); } break; case 'f': cpos = getpos(curx, cury, curpos); format++; if (format > 2) format = 0; calccols(); *curpos = cpos - (*cury * bcol + *curx / divf); if (*curpos < 0) { *curpos = 0; *cury = cpos / bcol; *curx = (cpos - (*cury * bcol)) * divf; } movepos(curx, cury); rfresh = 1; break; case 'l': do { (*curx) += divf; if (getpos(curx, cury, curpos) >= filesize) (*curx) -= divf; if (*curx >= eol) { *curx = 0; (*cury)++; if (*cury >= LINES - 1) { (*cury)--; if (pagend < filesize) { (*curpos) += bcol; rfresh = 1; } } } } while (--count > 0); break; case 'h': do { (*curx) -= divf; if (*curx < 0 && *cury == 0 && *curpos == 0) { *curx = 0; break; } else if (*curx < 0) { (*curx) = eol - 1; (*cury)--; movepos(curx, cury); if (*cury < 0) { (*cury)++; if (*curpos >= bcol) { (*curpos) -= bcol; rfresh = 1; } else if (*curpos > 0) { (*curpos)--; rfresh = 1; } } } } while (--count > 0); break; case '\025': temp = count; count = 0; do { for (i = 0; i < LINES >> 1; i++) dokeyhandle('k', curx, cury, curpos); } while (--temp > 0); rfresh = 1; break; case '\004': temp = count; count = 0; do { for (i = 0; i < LINES >> 1; i++) dokeyhandle('j', curx, cury, curpos); } while (--temp > 0); rfresh = 1; break; case '\014': rfresh = 1; break; case 'k': do { (*cury)--; if (*cury < 0) { (*cury)++; if (*curpos >= bcol) { (*curpos) -= bcol; rfresh = 1; } else if (*curpos > 0) { cpos = getpos(curx, cury, curpos); *curpos = 0; *cury = cpos / bcol; *curx = (cpos - (*cury * bcol)) * divf; rfresh = 1; } } } while (--count > 0); break; case 'j': do { (*cury)++; if (*cury >= LINES - 1) { (*cury)--; if (pagend < filesize) { (*curpos) += bcol; rfresh = 1; } } if (getpos(curx, cury, curpos) >= filesize) (*cury)--; } while (--count > 0); break; case '0': *curx = 0; break; case '$': *curx = COLS - 1; movepos(curx, cury); break; case ']': keyin = getch(); if (keyin != ']') break; case 'G': *curpos = filesize - ((LINES - 2) * bcol); *curx = 0; *cury = LINES - 3; rfresh = 1; break; case '\007': cpos = getpos(curx, cury, curpos); mvprintw(LINES - 1, 0, "File: %s %s%s Position: %d of %d (line %d of %d)", infile, mod ? "[modified]" : "", writeprot ? "[write-protected]" : "", cpos, filesize - 1, (int) (cpos / COLS) + 1, (int)(filesize / COLS) + 1); clrtoeol(); break; case '[': keyin = getch(); if (keyin == '[') { *curpos = 0; *curx = 0; *cury = 0; rfresh = 1; } break; case 'Z': keyin = getch(); if (keyin != 'Z') break; linein[0] = 'w'; linein[1] = '\0'; rfresh = 2; if (mod > 0) goto writefile; else { mvprintw(LINES - 1, 0, "No changes made to %s", infile); clrtoeol(); break; } case '/': move(LINES - 1, 0); clrtoeol(); move(LINES - 1, 0); addch(keyin); echo(); getstr(sstr); noecho(); /* interpret search string in context of format */ if (format == 1) { char *sptr1 = sstr, tmp[5], *sptr2 = sstr; int hexdig; while (*sptr1 != '\n' && *sptr1 != '\0') { if (!isspace(*sptr1) && !isxdigit(*sptr1) && *sptr1 != 'x') { beep(); mvprintw(LINES - 1, 0, "Use hex numbers in hex format"); clrtoeol(); break; } sptr1++; } sptr1 = sstr; while (*sptr1 != '\n' && *sptr1 != '\0') { while (isspace(*sptr1)) sptr1++; if (*sptr1 == '\0') break; tmp[0] = *sptr1++; tmp[1] = *sptr1++; if (tmp[1] == 'x') { tmp[2] = *sptr1++; tmp[3] = *sptr1++; tmp[4] = '\0'; sscanf(tmp, "%x", &hexdig); } else { tmp[2] = '\0'; hexdig = strtol(&tmp, NULL, 16); } *sptr2++ = (char) hexdig; } *sptr2 = '\0'; length = (int)(sptr2 - sstr); } else if (format == 0) { char *sptr1 = sstr, *sptr2 = sstr; int decdig; while (*sptr1 != '\n' && *sptr1 != '\0') { if (!isdigit(*sptr1) && !isspace(*sptr1)) { beep(); mvprintw(LINES - 1, 0, "Use decimal digits in decimal format"); clrtoeol(); break; } sptr1++; } sptr1 = sstr; while (*sptr1 != '\n' && *sptr1 != '\0') { sscanf(sptr1, "%d", &decdig); if (decdig > 255) { beep(); mvprintw(LINES - 1, 0, "Entry larger than byte or space missing"); clrtoeol(); break; } while (!isdigit(*sptr1++)); while (isdigit(*sptr1++)); *sptr2++ = (char) decdig; } *sptr2 = '\0'; length = (int)(sptr2 - sstr); } else length = strlen(sstr); case 'n': do { searchptr = getpos(curx, cury, curpos); tmpptr = searchptr; if (length == 0) { beep(); mvprintw(LINES - 1, 0, "No search string specified"); clrtoeol(); break; } mvprintw(LINES - 1, 0, "Searching for %s\n", sstr); clrtoeol(); /* Do the search */ if ((searchptr = searchstr()) >= filesize) break; /* Go to item */ if (searchptr > *curpos && searchptr < *curpos + (LINES * bcol)) { *cury = (searchptr - *curpos) / bcol; *curx = ((searchptr - *curpos) % bcol) * divf; } else { *curx = (bcol >> 1) * divf; *cury = LINES >> 1; *curpos = searchptr - (*cury * bcol) - (*curx / divf); if (*curpos < 0) { *curpos = 0; *cury = searchptr / bcol; *curx = (searchptr % bcol) * divf; } rfresh = 1; } if (tmpptr >= searchptr) { mvprintw(LINES - 1, 0, "Search wrapped to beginning of file"); clrtoeol(); } } while (--count > 0); break; case ':': move(LINES - 1, 0); clrtoeol(); move(LINES - 1, 0); addch(keyin); echo(); getstr(linein); noecho(); writefile: if (linein[0] == 'q') { return 2; } else if (linein[0] == 'w') { if (strlen(linein) > 3) { infile = &linein[2]; fd = fi; if ((fi = fopen(infile, "w")) == NULL) { mvprintw(LINES - 1, 0, "Unable to open file for writing"); clrtoeol(); fi = fd; return; } else fclose(fd); } else if (infile == NULL) { beep(); mvprintw(LINES - 1, 0, "No file name: use :w filename"); clrtoeol(); return; } /* write the file */ mvprintw(LINES - 1, 0, "Writing file %s", infile); clrtoeol(); rewind(fi); for (i = 0; i < filesize; i++) fprintf(fi, "%c", inbuf[i]); } else if (isdigit(linein[0])) { long int lineto; if (sscanf(linein, "%d", &lineto) == 1) { long int savepos = *curpos; lineto--; *cury = LINES >> 1; *curpos = lineto * COLS - (*cury * bcol); if (*curpos < 0) { *curpos = 0; *cury = (lineto * COLS) / bcol; } if (getpos(curx, cury, curpos) >= filesize) { *curpos = savepos; beep(); mvprintw(LINES - 1, 0, "Not that many lines in buffer"); clrtoeol(); } if (savepos != *curpos) rfresh = 1; } } break; } count = 0; } return rfresh; } /*--------------------------------------------------------*/ /* Shell for basic editing routine */ /*--------------------------------------------------------*/ edit() { int keyin; short curx = 0, cury = 0, rfresh = 0; long int curpos = 0; length = 0; printscr(&curpos); mvprintw(LINES - 1, 0, "Editing: %s %s Size: %d bytes", infile, writeprot ? "[Write-Protected]" : "", filesize); move(cury, curx); calccols(); while (rfresh != 2) { keyin = getch(); rfresh = dokeyhandle(keyin, &curx, &cury, &curpos); if (rfresh) { erase(); printscr(&curpos); } move(cury, curx); } } /*--------------------------------------------------------*/ /* Print the data to the screen starting at position spos */ /* and clipping left edge at ncol columns */ /*--------------------------------------------------------*/ printscr(spos) long int *spos; { short i, j = 0; char *fptr = inbuf + *spos; if (format == 0) /* decimal format */ for (j = 0; j < LINES - 1 && fptr - inbuf < filesize; j++) for (i = 0; i < (COLS >> 2) && fptr - inbuf < filesize; i++) mvprintw(j, i << 2, "%3d", (int)(*fptr++)); else if (format == 1) /* hex format */ for (j = 0; j < LINES - 1 && fptr - inbuf < filesize; j++) for (i = 0; i < (COLS / 3) && fptr - inbuf < filesize; i++) { mvprintw(j, i * 3, "%2x", (int)(*fptr)); if (*fptr < 16) mvprintw(j, i * 3, "0"); fptr++; } else if (format == 2) /* character format */ for (j = 0; j < LINES - 1 && fptr - inbuf < filesize; j++) for (i = 0; i < COLS && fptr - inbuf < filesize; i++) if (isprint(*fptr)) mvprintw(j, i, "%c", *fptr++); else { move(j,i); addch(ACS_BLOCK); fptr++; } if (fptr - inbuf >= filesize) for (; j < LINES - 1; j++) mvprintw(j, 0, "~"); } /*--------------------------------------------------------*/ /* main program (startup curses package) */ /*--------------------------------------------------------*/ main(argc, argv) int argc; char *argv[]; { char inchar; long int i; mod = 0; writeprot = 0; format = 0; curbufs = 1; count = 0; inbuf = (char *)malloc(BUFSIZE * sizeof(char)); if (argc == 2) { /* load in file */ infile = argv[1]; if ((fi = fopen(infile, "r+")) == NULL) if ((fi = fopen(infile, "r")) == NULL) printf("Unable to find file %s", infile); else writeprot = 1; if (fi != NULL) { i = 0; while ((fscanf(fi, "%c", &inchar)) != EOF) { inbuf[i++] = inchar; if (i >= BUFSIZE * curbufs) if ((inbuf = (char *) realloc(inbuf, (++curbufs) * BUFSIZE * sizeof(char))) == NULL) { printf("Error: Out of memory at %d bytes!\n", BUFSIZE * (curbufs - 1)); exit(0); } } } filesize = i; } else { filesize = 0; infile = (char *)malloc(sizeof(char)); *infile = '\0'; } initscr(); cbreak(); noecho(); /* run editor */ edit(); /* wrap up curses routines and deallocate memory */ endwin(); free(inbuf); fclose(fi); }