view src/unexnext.c @ 1719:48f539ac6921

* frame.h (struct frame): New fields `can_have_scrollbars' and `has_vertical_scrollbars'. (FRAME_CAN_HAVE_SCROLLBARS, FRAME_HAS_VERTICAL_SCROLLBARS): New accessors, for both the MULTI_FRAME and non-MULTI_FRAME. (VERTICAL_SCROLLBAR_WIDTH, WINDOW_VERTICAL_SCROLLBAR, WINDOW_VERTICAL_SCROLLBAR_COLUMN, WINDOW_VERTICAL_SCROLLBAR_HEIGHT): New macros. * window.h (struct window): New field `vertical_scrollbar'. * xterm.h (struct x_display): vertical_scrollbars, judge_timestamp, vertical_scrollbar_extra: New fields. (struct scrollbar): New struct. (VERTICAL_SCROLLBAR_PIXEL_WIDTH, VERTICAL_SCROLLBAR_PIXEL_HEIGHT, VERTICAL_SCROLLBAR_LEFT_BORDER, VERTICAL_SCROLLBAR_RIGHT_BORDER, VERTICAL_SCROLLBAR_TOP_BORDER, VERTICAL_SCROLLBAR_BOTTOM_BORDER, CHAR_TO_PIXEL_WIDTH, CHAR_TO_PIXEL_HEIGHT, PIXEL_TO_CHAR_WIDTH, PIXEL_TO_CHAR_HEIGHT): New accessors and macros. * frame.c (make_frame): Initialize the `can_have_scrollbars' and `has_vertical_scrollbars' fields of the frame. * term.c (term_init): Note that TERMCAP terminals don't support scrollbars. (mouse_position_hook): Document new args. (set_vertical_scrollbar_hook, condemn_scrollbars_hook, redeem_scrollbar_hook, judge_scrollbars_hook): New hooks. * termhooks.h: Declare and document them. (enum scrollbar_part): New type. (struct input_event): Describe the new form of the scrollbar_click event type. Change `part' from a Lisp_Object to an enum scrollbar_part. Add a new field `scrollbar'. * keyboard.c (kbd_buffer_get_event): Pass appropriate new parameters to *mouse_position_hook, and make_lispy_movement. * xfns.c (x_set_vertical_scrollbar): New function. (x_figure_window_size): Use new macros to calculate frame size. (Fx_create_frame): Note that X Windows frames do support scroll bars. Default to "yes". * xterm.c: #include <X11/cursorfont.h> and "window.h". (x_vertical_scrollbar_cursor): New variable. (x_term_init): Initialize it. (last_mouse_bar, last_mouse_bar_frame, last_mouse_part, last_mouse_scroll_range_start, last_mouse_scroll_range_end): New variables. (XTmouse_position): Use them to return scrollbar movement events. Take new arguments, for that purpose. (x_window_to_scrollbar, x_scrollbar_create, x_scrollbar_set_handle, x_scrollbar_remove, x_scrollbar_move, XTset_scrollbar, XTcondemn_scrollbars, XTredeem_scrollbar, XTjudge_scrollbars, x_scrollbar_expose, x_scrollbar_background_expose, x_scrollbar_handle_click, x_scrollbar_handle_motion): New functions to implement scrollbars. (x_term_init): Set the termhooks.h hooks to point to them. (x_set_window_size): Use new macros to calculate frame size. Set vertical_scrollbar_extra field. (x_make_frame_visible): Use the frame accessor FRAME_HAS_VERTICAL_SCROLLBARS to decide if we need to map the frame's subwindows as well. (XTread_socket): Use new size-calculation macros from xterm.h when processing ConfigureNotify events. (x_wm_set_size_hint): Use PIXEL_TO_CHAR_WIDTH and PIXEL_TO_CHAR_HEIGHT macros. * ymakefile (xdisp.o): This now depends on termhooks.h. (xterm.o): This now depends on window.h. * xterm.h (struct x_display): Delete v_scrollbar, v_thumbup, v_thumbdown, v_slider, h_scrollbar, h_thumbup, h_thumbdown, h_slider, v_scrollbar_width, h_scrollbar_height fields. * keyboard.c (Qvscrollbar_part, Qvslider_part, Qvthumbup_part, Qvthumbdown_part, Qhscrollbar_part, Qhslider_part, Qhthumbup_part, Qhthumbdown_part, Qscrollbar_click): Deleted; part of an obsolete interface. (head_table): Removed from here as well. (syms_of_keyboard): And here. * keyboard.h: And here. (POSN_SCROLLBAR_BUTTON): Removed. * xscrollbar.h: File removed - no longer necessary. * xfns.c: Don't #include it any more. (Qhorizontal_scroll_bar, Qvertical_scroll_bar): Deleted. (syms_of_xfns): Don't initialize or staticpro them. (gray_bits): Salvaged from xscrollbar.h. (x_window_to_scrollbar): Deleted. (x_set_horizontal_scrollbar): Deleted. (enum x_frame_parm, x_frame_parms): Remove references to x_set_horizontal_scrollbar. (x_set_foreground_color, x_set_background_color, x_set_border_pixel): Remove special code to support scrollbars. (Fx_create_frame): Remove old scrollbar setup code. (install_vertical_scrollbar, install_horizontal_scrollbar, adjust_scrollbars, x_resize_scrollbars): Deleted. * xterm.c (construct_mouse_click): This doesn't need to take care of scrollbar clicks anymore. (XTread_socket): Remove old code to support scrollbars. Call new functions instead for events which occur in scrollbar windows. (XTupdate_end): Remove call to adjust_scrollbars; the main redisplay code takes care of that now. (enum window_type): Deleted. * ymakefile: Note that xfns.o no longer depends on xscrollbar.h. * xfns.c (syms_of_xfns): Delete defvars for x_mouse_x and x_mouse_y. That interface hasn't been live for years. (x_mouse_x, x_mouse_y): Delete these variables. * xfns.c (Fx_create_frame): Don't initialize the wm_hints field here. (x_window): Do it here, along with all the similar stuff. It's a pain to remember that you can't assign to FRAME->visible. Let's change all references to the `visible' member of struct frame to use the accessor macros, and then write a setter for the `visible' field that does the right thing. * frame.h (FRAME_VISIBLE_P): Make this not an l-value. (FRAME_SET_VISIBLE): New macro. * frame.c (make_terminal_frame, Fdelete_frame): Use FRAME_SET_VISIBLE. (Fframe_visible_p, Fvisible_frame_list): Use FRAME_VISIBLE_P and FRAME_ICONIFIED_P. * dispnew.c (Fredraw_display): Use the FRAME_VISIBLE_P and FRAME_GARBAGED_P accessors. * xdisp.c (redisplay): Use the FRAME_VISIBLE_P accessor. * xfns.c (x_set_foreground_color, x_set_background_color, x_set_cursor_color, x_set_border_pixel, x_set_icon_type): Use the FRAME_VISIBLE_P accessor. (Fx_create_frame): Use FRAME_SET_VISIBILITY. * xterm.c (clear_cursor, x_display_bar_cursor, x_display_box_cursor): Use FRAME_SET_VISIBILITY.
author Jim Blandy <jimb@redhat.com>
date Thu, 24 Dec 1992 06:19:31 +0000
parents 5f7b21303f10
children b70f4760d769
line wrap: on
line source

/* Dump Emacs in macho format.
   Copyright (C) 1990 Free Software Foundation, Inc.
   Written by Bradley Taylor (btaylor@next.com).

This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.

GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING.  If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */


#undef __STRICT_BSD__

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <mach.h>
#include <sys/loader.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <libc.h>


extern struct section *getsectbyname(char *, char *);

/*
 * Kludge: we don't expect any program data beyond VM_HIGHDATA
 * What is really needed is a way to find out from malloc() which
 * pages it vm_allocated and write only those out into the data segment.
 *
 * This kludge may break when we stop using fixed virtual address
 * shared libraries. Actually, emacs will probably continue working, but be 
 * much larger on disk than it needs to be (because non-malloced data will
 * be in the file).
 */
static const unsigned VM_HIGHDATA = 0x2000000;

typedef struct region_t {
	vm_address_t address;
	vm_size_t size;
	vm_prot_t protection;
	vm_prot_t max_protection;
	vm_inherit_t inheritance;
	boolean_t shared;
	port_t object_name;
	vm_offset_t offset;
} region_t;


static void
grow(
     struct load_command ***the_commands,
     unsigned *the_commands_len
     )
{
	if (*the_commands == NULL) {
		*the_commands_len = 1;
		*the_commands = malloc(sizeof(*the_commands));
	} else {
		(*the_commands_len)++;
		*the_commands = realloc(*the_commands, 
					(*the_commands_len *
					 sizeof(**the_commands)));
	}
}


static void
save_command(
	     struct load_command *command,
	     struct load_command ***the_commands,
	     unsigned *the_commands_len
	     )
{
	struct load_command **tmp;

	grow(the_commands, the_commands_len);
	tmp = &(*the_commands)[*the_commands_len - 1];
	*tmp = malloc(command->cmdsize);
	bcopy(command, *tmp, command->cmdsize);
}

static void
fatal_unexec(char *format, ...)
{
	va_list ap;

	va_start(ap, format);
	fprintf(stderr, "unexec: ");
	vfprintf(stderr, format, ap);
	fprintf(stderr, "\n");
	va_end(ap);
}

static int
read_macho(
	   int fd,
	   struct mach_header *the_header,
	   struct load_command ***the_commands,
	   unsigned *the_commands_len
	   )
{
	struct load_command command;
	struct load_command *buf;
	int i;
	int size;

	if (read(fd, the_header, sizeof(*the_header)) != sizeof(*the_header)) {
		fatal_unexec("cannot read macho header");
		return (0);
	}
	for (i = 0; i < the_header->ncmds; i++) {
		if (read(fd, &command, sizeof(struct load_command)) != 
		    sizeof(struct load_command)) {
		  	fatal_unexec("cannot read macho load command header");
			return (0);
		}
		size = command.cmdsize - sizeof(struct load_command);
		if (size < 0) {
		  	fatal_unexec("bogus load command size");
			return (0);
		}
		buf = malloc(command.cmdsize);
		buf->cmd = command.cmd;
		buf->cmdsize = command.cmdsize;
		if (read(fd, ((char *)buf + 
			      sizeof(struct load_command)), 
			 size) != size) {
		  	fatal_unexec("cannot read load command data");
			return (0);
		}
		save_command(buf, the_commands, the_commands_len);
	}
	return (1);
}

static int
filldatagap(
	    vm_address_t start_address,
	    vm_size_t *size,
	    vm_address_t end_address
	    )
{
	vm_address_t address;
	vm_size_t gapsize;

	address = (start_address + *size);
	gapsize = end_address - address;
	*size += gapsize;
	if (vm_allocate(task_self(), &address, gapsize,
			FALSE) != KERN_SUCCESS) {
		fatal_unexec("cannot vm_allocate");
	        return (0);
	}
	return (1);
}

static int
get_data_region(
		vm_address_t *address,
		vm_size_t *size
		)
{
	region_t region;
	kern_return_t ret;
	struct section *sect;

	sect = getsectbyname(SEG_DATA, SECT_DATA);
	region.address = 0;
	*address = 0;
	for (;;) {
		ret = vm_region(task_self(), 
				&region.address, 
				&region.size, 
				&region.protection, 
				&region.max_protection, 
				&region.inheritance,
				&region.shared, 
				&region.object_name, 
				&region.offset);
		if (ret != KERN_SUCCESS || region.address >= VM_HIGHDATA) {
			break;
		}
		if (*address != 0) {
			if (region.address > *address + *size) {
				if (!filldatagap(*address, size, 
						 region.address)) {
					return (0);
				}
			} 
			*size += region.size;
		} else {
			if (region.address == sect->addr) {
				*address = region.address;
				*size = region.size;
			} 
		}
		region.address += region.size;
	}
	return (1);
}

static char *
my_malloc(
	  vm_size_t size
	  )
{
	vm_address_t address;

	if (vm_allocate(task_self(), &address, size, TRUE) != KERN_SUCCESS) {
		return (NULL);
	}
	return ((char *)address);
}

static void
my_free(
	char *buf,
	vm_size_t size
	)
{
	vm_deallocate(task_self(), (vm_address_t)buf, size);
}

static int
unexec_doit(
	    int infd,
	    int outfd
	    )
{
	int i;
	struct load_command **the_commands = NULL;
	unsigned the_commands_len;
	struct mach_header the_header;
	int fgrowth;
	int fdatastart;
	int fdatasize;
	int size;
	struct stat st;
	char *buf;
	vm_address_t data_address;
	vm_size_t data_size;

	struct segment_command *segment;

	if (!read_macho(infd, &the_header, &the_commands, &the_commands_len)) {
		return (0);
	}


	{
	  extern int malloc_cookie;
	  malloc_cookie = malloc_freezedry();
	}
	if (!get_data_region(&data_address, &data_size)) {
		return (0);
	}


	/*
	 * DO NOT USE MALLOC IN THIS SECTION
	 */
	{
		/*
		 * Fix offsets
		 */
		for (i = 0; i < the_commands_len; i++) {
			switch (the_commands[i]->cmd) {
			case LC_SEGMENT:
				segment = ((struct segment_command *)
					   the_commands[i]);
				if (strcmp(segment->segname, SEG_DATA) == 0) {
					fdatastart = segment->fileoff;
					fdatasize = segment->filesize;
					fgrowth = (data_size - 
						   segment->filesize);
					segment->vmsize = data_size;
					segment->filesize = data_size;
				}
				break;
			case LC_SYMTAB:
				((struct symtab_command *)
				 the_commands[i])->symoff += fgrowth;
				((struct symtab_command *)
				 the_commands[i])->stroff += fgrowth;
				break;
			case LC_SYMSEG:
				((struct symseg_command *)
				 the_commands[i])->offset += fgrowth;
				break;
			default:
				break;
			}
		}
		
		/*
		 * Write header
		 */
		if (write(outfd, &the_header, 
			  sizeof(the_header)) != sizeof(the_header)) {
			fatal_unexec("cannot write output file");
			return (0);
		}
		
		/*
		 * Write commands
		 */
		for (i = 0; i < the_commands_len; i++) {
			if (write(outfd, the_commands[i], 
				  the_commands[i]->cmdsize) != 
			    the_commands[i]->cmdsize) {
			  	fatal_unexec("cannot write output file");
				return (0);
			}
		}
		
		/*
		 * Write original text
		 */
		if (lseek(infd, the_header.sizeofcmds + sizeof(the_header), 
			  L_SET) < 0) {
		  	fatal_unexec("cannot seek input file");
			return (0);
		}
		size = fdatastart - (sizeof(the_header) + 
				     the_header.sizeofcmds);
		buf = my_malloc(size);
		if (read(infd, buf, size) != size) {
			my_free(buf, size);
		  	fatal_unexec("cannot read input file");
		}
		if (write(outfd, buf, size) != size) {
			my_free(buf, size);
			fatal_unexec("cannot write output file");
			return (0);
		}
		my_free(buf, size);
		
		
		/*
		 * Write new data
		 */
		if (write(outfd, (char *)data_address, 
			  data_size) != data_size) {
			fatal_unexec("cannot write output file");
			return (0);
		}
		
	}

	/*
	 * OKAY TO USE MALLOC NOW
	 */

	/*
	 * Write rest of file
	 */
	fstat(infd, &st);
	if (lseek(infd, fdatasize, L_INCR) < 0) {
		fatal_unexec("cannot seek input file");
		return (0);
	}
	size = st.st_size - lseek(infd, 0, L_INCR);

	buf = malloc(size);
	if (read(infd, buf, size) != size) {
		free(buf);
		fatal_unexec("cannot read input file");
		return (0);
	}
	if (write(outfd, buf, size) != size) {
		free(buf);
		fatal_unexec("cannot write output file");
		return (0);
	}
	free(buf);
	return (1);
}

void
unexec(
       char *outfile,
       char *infile
       )
{
	int infd;
	int outfd;
	char tmpbuf[L_tmpnam];
	char *tmpfile;

	infd = open(infile, O_RDONLY, 0);
	if (infd < 0) {
	  	fatal_unexec("cannot open input file `%s'", infile);
		exit(1);
	}
	
	tmpnam(tmpbuf);
	tmpfile = rindex(tmpbuf, '/');
	if (tmpfile == NULL) {
		tmpfile = tmpbuf;
	} else {
		tmpfile++;
	}
	outfd = open(tmpfile, O_WRONLY|O_TRUNC|O_CREAT, 0755);
	if (outfd < 0) {
		close(infd);
		fatal_unexec("cannot open tmp file `%s'", tmpfile);
		exit(1);
	}
	if (!unexec_doit(infd, outfd)) {
		close(infd);
		close(outfd);
		unlink(tmpfile);
		exit(1);
	}
	close(infd);
	close(outfd);
	if (rename(tmpfile, outfile) < 0) {
		unlink(tmpfile);
		fatal_unexec("cannot rename `%s' to `%s'", tmpfile, outfile);
		exit(1);
	}
}