view src/unexnext.c @ 1787:5e245540d06f

Make scrollbar structures into lisp objects, so that they can be GC'd; this allows windows and scrollbars can refer to each other without worrying about dangling pointers. * xterm.h (struct x_display): vertical_scrollbars and judge_timestamp members deleted. (struct scrollbar): Redesigned to be a template for a Lisp_Vector. (SCROLLBAR_VEC_SIZE, XSCROLLBAR, SCROLLBAR_PACK, SCROLLBAR_UNPACK, SCROLLBAR_X_WINDOW, SET_SCROLLBAR_X_WINDOW, VERTICAL_SCROLLBAR_INSIDE_WIDTH, VERTICAL_SCROLLBAR_TOP_RANGE, VERTICAL_SCROLLBAR_INSIDE_HEIGHT, VERTICAL_SCROLLBAR_MIN_HANDLE): New macros, to help deal with the lispy structures, and deal with the graphics. * frame.h (WINDOW_VERTICAL_SCROLLBAR): Macro deleted. (struct frame): New fields `scrollbars' and `condemned_scrollbars', for use by the scrollbar implementation. [MULTI_FRAME and not MULTI_FRAME] (FRAME_SCROLLBARS, FRAME_CONDEMNED_SCROLLBARS): Accessors for the new field. * window.h (struct window): Doc fix for vertical_scrollbar field. * frame.c (make_frame): Initialize the `scrollbars' and `condemned_scrollbars' fields of the new frame. * alloc.c (mark_object): Mark the `scrollbars' and `condemned_scrollbars' slots of frames. * xterm.c (x_window_to_scrollbar): Scrollbars are chained on frames' scrollbar field, not their x.display->vertical_scrollbars field. (x_scrollbar_create, x_scrollbar_set_handle, x_scrollbar_move, x_scrollbar_remove, XTset_vertical_scrollbar, XTcondemn_scrollbars, XTredeem_scrollbar, XTjudge_scrollbars, x_scrollbar_expose, x_scrollbar_handle_click, x_scrollbar_handle_motion): Substantially rewritten to correct typos and brainos, and to accomodate the lispy structures. * xterm.c (x_scrollbar_background_expose): Function deleted; we don't want anything in the background there after all. (XTread_socket): Don't call x_scrollbar_background_expose. We don't care. * xterm.h (CHAR_TO_PIXEL_WIDTH, CHAR_TO_PIXEL_HEIGHT, PIXEL_TO_CHAR_WIDTH, PIXEL_TO_CHAR_HEIGHT): Rewritten, using: (CHAR_TO_PIXEL_ROW, CHAR_TO_PIXEL_COL, PIXEL_TO_CHAR_ROW, PIXEL_TO_CHAR_COL): New macros. * xfns.c [not HAVE_X11] (Fx_create_frame): Use the PIXEL_TO_CHAR_{HEIGHT,WIDTH} macros to figure the frame's character size, and the CHAR_TO_PIXEL* macros for vice versa. * xterm.c (XTwrite_glyphs, XTclear_end_of_line, stufflines, scraplines, dumprectangle, pixel_to_glyph_coords, x_draw_box, clear_cursor, x_display_bar_cursor, x_draw_single_glyph, x_set_mouse_position): Use the CHAR_TO_PIXEL_* macros. * xterm.c (x_wm_set_size_hint): The max_width and max_height members of the size_hints are expressed in pixels, not columns. * xterm.c (x_set_window_size): Remove ibw var; it's not used. Set FRAME_WIDTH (f) to cols instead of rows. Duh. * xterm.c (pixel_to_glyph_coords): Properly set *bounds to the character cell bounding the position, even when the position is off the frame. * termhooks.h (mouse_position_hook): Doc fix. (set_vertical_scrollbar_hook): This doesn't return anything any more, and doesn't take a struct scrollbar * argument any more. (condemn_scrollbars_hook, redeem_scrollbar_hook, judge_scrollbars_hook): Doc fixes. * term.c (mouse_position_hook): Doc fix. (set_vertical_scrollbar_hook): This doesn't return anything any more. Doc fixes. * keyboard.c (kbd_buffer_get_event): Receive the scrollbar's window from *mouse_position_hook and pass it to make_lispy_movement, instead of working with a pointer to a struct scrollbar. (make_lispy_event): We don't need a window_from_scrollbar function anymore; we are given the window directly in *EVENT. Unify the code which generates text-area mouse clicks and scrollbar clicks; use the same code to distinguish clicks from drags on the scrollbar as in the text area. Distinguish clicks from drags by storing a copy of the lispy position list returned as part of the event. (button_down_location): Make this a lisp vector, rather than an array of random structures. (struct mouse_position): Remove this; it's been replaced by a lisp list. (make_lispy_movement): Accept the scrollbar's window as a parameter, rather than the scrollbar itself. If FRAME is zero, assume that the other arguments are garbage. (syms_of_keyboard): No need to staticpro each window of button_down_location now; just initialize and staticpro it. * window.c (window_from_scrollbar): Function deleted; no longer needed. * xdisp.c (redisplay_window): Just pass the window to set_vertical_scrollbar hook; don't pass the scrollbar object too. * xterm.c (XTmouse_position): Don't return a pointer to the scrollbar for scrollbar motion; instead, return the scrollbar's window. * xterm.c (XTmouse_position): Entirely rewritten, using XTranslateCoordinates. Call x_scrollbar_report_motion to handle scrollbar movement events. (x_scrollbar_report_motion): New function, to help out XTmouse_position. * termhooks.h (struct input_event): Replace the frame member with a Lisp_Object member by the name of frame_or_window. Doc fixes. Remove the scrollbar member; instead, use frame_or_window to hold the window whose scrollbar was clicked. * keyboard.c (kbd_buffer_store_event, kbd_buffer_get_event, make_lispy_event): Adjust references to frame member of struct input_event to use frame_or_window now. * xterm.c (construct_mouse_click, XTread_socket): Same. * xterm.c (last_mouse_bar, last_mouse_bar_frame, last_mouse_part, last_mouse_scroll_range_start, last_mouse_scroll_range_end): Replaced with... (last_mouse_scrollbar): New variable. (note_mouse_movement): Clear last_mouse_scrollbar when we have receieved a new motion. (syms_of_xterm): Staticpro last_mouse_scrollbar. * xterm.c (note_mouse_position): Renamed to note_mouse_movement, because that's what it really does. (x_scrollbar_handle_motion): Renamed to x_scrollbar_note_movement, for consistency. (XTread_socket): Adjusted. * xterm.c (XTset_scrollbar): Renamed to XTset_vertical_scrollbar. (x_term_init): Adjusted. * emacs.c (shut_down_emacs): New function. (fatal_error_signal, Fkill_emacs): Call it, instead of writing it out. * xterm.c (x_connection_closed): Call shut_down_emacs instead of Fkill_emacs; the latter will try to perform operations on the X server and die a horrible death. * lisp.h (shut_down_emacs): Add extern declaration for it. * xterm.c (x_error_quitter): Move the abort call to after we print the error message. No harm in that.
author Jim Blandy <jimb@redhat.com>
date Thu, 14 Jan 1993 15:34:14 +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);
	}
}