⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 heme.c

📁 heme is an interface for controlling unix
💻 C
📖 第 1 页 / 共 3 页
字号:
#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <sys/stat.h>#include <pwd.h>#include <curses.h>#ifdef HAVE_MMAP# include <sys/mman.h>#endif#include "xmalloc.h"#include "pconfig.h"#include "pgetopt.h"/* this determines maximum memory that will be * available for blocks (default: 2 MB) */#define MAX_BLOCKMEM	(2 * (1 << 20))	static const char heme_version[] = "0.4.2";typedef unsigned char byte;static WINDOW *w_main, *w_offset, *w_ascii;static int max_lines;static off_t cur_offset, beg_offset, end_offset, file_size;static int mode_ascii;static int fd;static int file_saved = 1;static int cur_line;static char *file_name;static char *prog_name;static const char *config_file;static int current_nibble;static int last_search = -1; /* 0 = byte search, 1 = string search */static int last_byte_search = 0;static char *last_string_search = NULL;static off_t off_len;static int bpl;	/* bytes per line *//* undo struct used by put_byte */typedef struct {	off_t offset1, offset2;	byte b;	byte *fill_bytes;}undo_t;static undo_t *undo_list;static int undo_count;typedef struct {	byte *buf;	off_t off_start, off_len;	int modified;}blist_t;static blist_t *blist;static int blist_count;static int blist_current;	/* index of current block */static int use_colors = -1;static void save_undo_info(off_t offset, byte b);static int make_backup_files = -1;static int advance_after_edit = -1;static void advance_right();/* reads file into buf, max n bytes, returns 0 on EOF, < 0 on error */static ssize_t read_file(int fds, byte *buf, size_t n){	ssize_t i;	size_t sum = 0;	while(sum < n)	{		i = read(fds, buf, n);		if(i < 0)			return i;		else if(i == 0)			return sum;		sum += i;	}	return sum;}static void write_block(int i, int fds){	off_t len;	/* error checking ??? */	lseek(fds, blist[i].off_start, SEEK_SET);	/* check for eof */	len = blist[i].off_len;	if(blist[i].off_start + len > file_size)		len = file_size - blist[i].off_start;	write(fds, blist[i].buf, len);}static void save_file(int do_munmap){	int i;	if(make_backup_files)	{		int backup_fd;		ssize_t r;		byte *tmp;		char *backup_name;		backup_name = xmalloc(strlen(file_name) + 2);		sprintf(backup_name, "%s~", file_name);		backup_fd = open(backup_name, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR |						 S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);		tmp = xmalloc(off_len);		lseek(fd, 0, SEEK_SET);		while((r = read_file(fd, tmp, off_len)) > 0)			write(backup_fd, tmp, r);		free(tmp);		close(backup_fd);		free(backup_name);	}	/* save all modified blocks */	for(i = 0; i < blist_count; i++)	{		if(blist[i].modified)		{			write_block(i, fd);#ifdef HAVE_MMAP			if(do_munmap)				munmap(blist[i].buf, blist[i].off_len);#endif			blist[i].modified = 0;		}	}	file_saved = 1;}static int find_block(off_t offset){	int i;	for(i = 0; i < blist_count; i++)	{		if(blist[i].off_start <= offset && offset < blist[i].off_start + blist[i].off_len)			return i;	}	return -1;}static void check_max_blocks(){	int i;	/* check if we reached max. number of blocks */	if((blist_count + 1) * off_len >= MAX_BLOCKMEM)	{		/* first attempt to free unmodified blocks */		for(i = 0; i < blist_count; i++)		{			if(blist[i].modified)				continue;			if(blist[i].off_start <= cur_offset && cur_offset < blist[i].off_start + blist[i].off_len)				continue;	/* ckip current block */#ifdef HAVE_MMAP			munmap(blist[i].buf, blist[i].off_len);#else			free(blist[i].buf);#endif			/* hack: move end block to this one's position in the list */			if(i != blist_count - 1)				blist[i] = blist[blist_count - 1];			blist_count--;			blist = xrealloc(blist, blist_count * sizeof(blist_t));			return;		}		/* if no blocks are unmodified (very unlikely for such large files, btw)		 * remove the first one */		if((blist_count + 1) * off_len >= MAX_BLOCKMEM)		{			write_block(0, fd);#ifdef HAVE_MMAP			munmap(blist[0].buf, blist[0].off_len);#else			free(blist[0].buf);#endif			/* hack: move end block to this one's position in the list */			if(blist_count != 1)				blist[0] = blist[blist_count - 1];			blist_count--;			blist = xrealloc(blist, blist_count * sizeof(blist_t));		}	}}static int load_block(off_t offset){	byte *buf;	off_t off_start;	/* we must allocate another block, check if we can */	check_max_blocks();	/* align on the block size */	for(off_start = offset; off_start % off_len != 0; off_start--)		;#ifndef HAVE_MMAP	lseek(fd, off_start, SEEK_SET);	buf = xmalloc(off_len);	/* with mmap this isn't needed */	if(read_file(fd, buf, off_len) < 0)	{		fprintf(stderr, "%s: read_file() failed, something's gone wrong", prog_name);		exit(1);	}#else	buf = mmap(0, off_len, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, off_start);	if(buf == MAP_FAILED)	{		fprintf(stderr, "%s: mmap() failed", prog_name);		exit(1);	}#endif	/* add this block to the list */	blist = xrealloc(blist, sizeof(blist_t) * (blist_count + 1));	blist[blist_count].buf = buf;	blist[blist_count].off_start = off_start;	blist[blist_count].off_len = off_len;	blist[blist_count].modified = 0;	return blist_count++;}static void open_file(const char *name){	struct stat st;	fd = open(name, O_RDWR);	if(fd < 0)	{		fprintf(stderr, "%s: open: %s\n", prog_name, strerror(errno));		exit(1);	}	if(fstat(fd, &st) < 0)	{		fprintf(stderr, "%s: fstat: %s\n", prog_name, strerror(errno));		close(fd);		exit(1);	}	file_name = xstrdup(name);	file_size = st.st_size;	if(file_size == 0)	{		close(fd);		fprintf(stderr, "%s: file size of `%s' is 0\n", prog_name, name);		exit(0);	}#ifndef HAVE_MMAP	off_len = st.st_blksize;#endif	load_block(0);}static void unhilite(){	mvwchgat(w_main, cur_line, (3 * (cur_offset % bpl)), 3,			A_NORMAL, use_colors, NULL);	mvwchgat(w_ascii, cur_line, cur_offset % bpl, 3,			A_NORMAL, use_colors, NULL);	touchwin(w_main);	touchwin(w_ascii);}static void hilite(){	if(use_colors)	{		mvwchgat(w_main, cur_line, (3 * (cur_offset % bpl)) + current_nibble, 1,				A_NORMAL, 2, NULL);		mvwchgat(w_ascii, cur_line, cur_offset % bpl, 1,				A_NORMAL, 2, NULL);	}	else	{		mvwchgat(w_main, cur_line, 3 * (cur_offset % bpl), 2,				A_STANDOUT, 0, NULL);		mvwchgat(w_ascii, cur_line, cur_offset % bpl, 1, 				A_BLINK, 0, NULL);	}	touchwin(w_main);	touchwin(w_ascii);}static byte get_byte(off_t offset){	int i;	i = blist_current;	if(blist[i].off_start > offset || offset >= blist[i].off_start + blist[i].off_len)	{		/* if it isn't in the current block, search already mapped area */		if((i = find_block(offset)) < 0)			i = load_block(offset);		blist_current = i;	}	return blist[i].buf[offset - blist[i].off_start];}static void put_byte(off_t offset, byte b){	int i;	/* search already mapped area */	if((i = find_block(offset)) < 0)		i = load_block(offset);	blist[i].buf[offset - blist[i].off_start] = b;	blist[i].modified = 1;	file_saved = 0;}static int printable(byte *c){	if(*c > 127 || !isprint(*c))	{		*c = '.';		return 0;	}	return 1;}/* on line number 'line' print 'bpl' bytes starting from 'offset' */static void put_line(int line, off_t offset){	int i;	byte b;	/* print offset */	mvwprintw(w_offset, line, 0, "%08X:", offset);	mvwchgat(w_offset, line, 9, 4, A_NORMAL, 1, NULL);	wmove(w_main, line, 0);	wclrtoeol(w_main);	wmove(w_ascii, line, 0);	wclrtoeol(w_ascii);	for(i = 0; i < bpl && offset < file_size; i++, offset++)	{		b = get_byte(offset);		mvwprintw(w_main, line, i * 3, "%02X ", b);		printable(&b);		mvwprintw(w_ascii, line, i, "%c", b);	}	/* this is ugly */	{		int y,x;		getmaxyx(w_main,y,x);		mvwchgat(w_main, line, i, x - i, A_NORMAL, 1, NULL);	}	while(i <= bpl)	{		mvwchgat(w_ascii, line, i, 1, A_NORMAL, 1, NULL);		i++;	}}static void put_status(){	byte b;	b = get_byte(cur_offset);	mvprintw(0, 0, " File: %s%c  size = %lu bytes  %3d%%  [%c]", file_name, file_saved ? ' ' : '*',			 file_size, beg_offset * 100 / ( end_offset + (end_offset == 0) ),			 mode_ascii ? 'A' : 'H' );	mvprintw(0, COLS - 19, "Press 'h' for help");	mvprintw(LINES - 1, 0, " offset: 0x%-8X (%10d)  "			 "char: %c\t hex = 0x%-02X dec = %-3d oct = %-8o",			 cur_offset, cur_offset, printable(&b) ? b : '?', b, b, b			 );	clrtoeol();	if(use_colors)	{		mvchgat(0, 0, -1, A_NORMAL, 3, NULL);		mvchgat(LINES - 1, 0, -1, A_NORMAL, 3, NULL);	}	else	{		mvchgat(0, 0, -1, A_STANDOUT, 0, NULL);		mvchgat(LINES - 1, 0, -1, A_STANDOUT, 0, NULL);	}}/* called when in hex mode */static void set_byte_part(byte b){	byte old_byte;	int shift;	if(current_nibble == 1)	{		shift = 0;	}	else	{		shift = 4;	}	if(isdigit(b))		b -= '0';	else		b = 10 + b - 'a';		old_byte = get_byte(cur_offset);	b = (b << shift) | (old_byte & (0xF << (4 - shift)));	if(b == old_byte)		return;	save_undo_info(cur_offset, old_byte);	put_byte(cur_offset, b);	mvwprintw(w_main, cur_line, 3 * (cur_offset % bpl), "%02X", b);	printable(&b);	mvwprintw(w_ascii, cur_line, cur_offset % bpl, "%c", b);	hilite();}/* called when in ascii mode */static void set_byte(byte b){	byte old_byte;		old_byte = get_byte(cur_offset);	if(b == old_byte)		return;	save_undo_info(cur_offset, old_byte);	put_byte(cur_offset, b);	mvwprintw(w_main, cur_line, 3 * (cur_offset % bpl), "%02X", b);	printable(&b);	mvwprintw(w_ascii, cur_line, cur_offset % bpl, "%c", b);	hilite();}static void save_undo_info(off_t offset, byte b){	int i;		i = undo_count++;		undo_list = xrealloc(undo_list, sizeof(undo_t) * undo_count);	undo_list[i].offset1 = offset;	undo_list[i].offset2 = 0;	undo_list[i].b = b;	file_saved = 0;}static void save_undo_fill_info(off_t offset1, off_t offset2){	int i;	off_t t;	i = undo_count++;		undo_list = xrealloc(undo_list, sizeof(undo_t) * undo_count);	undo_list[i].offset1 = offset1;	undo_list[i].offset2 = offset2;	undo_list[i].fill_bytes = xmalloc(offset2 - offset1 + 1);	for(t = 0; t <= offset2 - offset1; t++)		undo_list[i].fill_bytes[t] = get_byte(offset1 + t);	file_saved = 0;}static void do_undo(){	byte b;	off_t offset;	if(undo_count == 0)		return;	/* the difference between "fill" undo and normal undo is	 * that the "fill" undo struct has offset2 != 0 */	undo_count--;	if(undo_list[undo_count].offset2 == 0)	{		offset = undo_list[undo_count].offset1;		b = undo_list[undo_count].b;		put_byte(offset, b);		/* if this is in current view ... */		if(offset >= beg_offset && offset < beg_offset + bpl * max_lines)		{			unhilite();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -