📄 textsw_filter.c
字号:
#ifndef lint#ifdef sccsstatic char sccsid[] = "@(#)textsw_filter.c 1.1 92/07/30";#endif#endif/* * Copyright (c) 1986 by Sun Microsystems, Inc. *//* * Filter invocation routines for textsw package. */#include <suntool/primal.h>#include <suntool/textsw_impl.h>#include <fcntl.h>#include <signal.h>#include <vfork.h>#include <sys/errno.h>#include <sys/ioctl.h>#define FAIL -1#define INPUT 0#define OUTPUT 1#define STDIN 0#define STDOUT 1#define STDERR 2#define PIPSIZ 4096 /* See uipc_pipe.c */#define SLOP_SIZE 16#define REPLY_ERROR -1#define REPLY_OKAY 0#define REPLY_SEND 1/* performance: global cache of getdtablesize() */extern int dtablesize_cache;#define GETDTABLESIZE() \ (dtablesize_cache?dtablesize_cache:(dtablesize_cache=getdtablesize()))extern int errno;extern char *getlogindir();pkg_private Es_index textsw_do_input();static short unsigned type_for_filter_rec();static int event_code_for_filter_rec();/* WARNING: this is a hack to force the variable to be in memory. * this var gets changed somehow when it is in register in the * context of a vfork(); */static int execvp_failed;pkg_private Ev_mark_object textsw_add_mark_internal();extern Notify_value notify_default_wait3();static intinterpret_filter_reply(view, buffer, buffer_length, delta) Textsw_view view; char *buffer; int buffer_length; Es_index *delta;{ *delta = textsw_do_input(view, buffer, (long)buffer_length, TXTSW_UPDATE_SCROLLBAR_IF_NEEDED); if AN_ERROR(*delta != buffer_length) return(REPLY_ERROR); return(REPLY_OKAY);}/* * Ignores SIGPIPE so that write(2) to nonexistent or dead filter * does not cause parent (containing textsw) to terminate. *//* ARGSUSED */static Notify_valuetextsw_sigpipe_func(textsw, sig, mode) Textsw_folio textsw; /* Currently unused */ int sig; /* Currently unused */ Notify_signal_mode mode; /* Currently unused */{ return(NOTIFY_DONE);}static inttextsw_filter_selection(folio, fill_in) register Textsw_folio folio; register Textsw_selection_handle fill_in;/* Note: this routine guarantees to return a valid (but possibly empty) * selection, thus callers need not error check the return value. */{ textsw_init_selection_object(folio, fill_in, "", 0, FALSE); fill_in->type = textsw_func_selection_internal( folio, fill_in, EV_SEL_PRIMARY, 0); if (TFS_IS_ERROR(fill_in->type) || (fill_in->type & TFS_IS_OTHER)) { fill_in->last_plus_one = fill_in->first = ES_INFINITY; fill_in->type = EV_SEL_PRIMARY | TFS_IS_SELF; } if (fill_in->first < fill_in->last_plus_one) { textsw_set_selection(VIEW_REP_TO_ABS(folio->first_view), ES_INFINITY, ES_INFINITY, (unsigned) fill_in->type); } else { fill_in->type &= ~EV_SEL_PENDING_DELETE; } return(fill_in->type);}pkg_private inttextsw_call_filter(view, filter_argv) register Textsw_view view; char *filter_argv[];{ register Textsw_folio folio = FOLIO_FOR_VIEW(view); int filter_input, filter_output, result = 0; Es_index save_length; Ev_mark_object save_lpo_id; Ev_mark_object save_insert = NULL; int pid; Textsw_selection_object selection; Notify_func old_sigpipe = (Notify_func)0; Es_index ev_get_insert(); (void) textsw_filter_selection(folio, &selection); if (selection.type & EV_SEL_PENDING_DELETE) { save_length = selection.last_plus_one - selection.first; save_lpo_id = textsw_add_mark_internal(folio, selection.last_plus_one, TEXTSW_MARK_DEFAULTS); } pid = start_filter(filter_argv, &filter_input, &filter_output); if (pid == FAIL) { result = 1; goto NoFilterReturn; } ev_set(0, folio->views, EV_CHAIN_DELAY_UPDATE, TRUE, 0); if ((int) ev_get(folio->views, EV_CHAIN_LOWER_CONTEXT) != EV_NO_CONTEXT) save_insert = textsw_add_mark_internal(folio, ev_get_insert(folio->views), TEXTSW_MARK_MOVE_AT_INSERT); old_sigpipe = notify_set_signal_func((Notify_client)folio, textsw_sigpipe_func, SIGPIPE, NOTIFY_ASYNC); (void) notify_set_wait3_func((Notify_client)folio, notify_default_wait3, pid); /* Note that there is no meaningful old_wait3_func */ switch (talk_to_filter(view, filter_input, filter_output, selection.first, selection.last_plus_one, interpret_filter_reply)) { case 0: break; case 1: goto ErrorReturn; }NormalReturn: (void) close(filter_output); if ((result == 0) && (selection.type & EV_SEL_PENDING_DELETE)) { Es_index saved_lpo; saved_lpo = textsw_find_mark_internal(folio, save_lpo_id); if AN_ERROR(saved_lpo == ES_INFINITY) { } else { (void) textsw_delete_span(view, saved_lpo-save_length, saved_lpo, TXTSW_DS_ADJUST|TXTSW_DS_SHELVE); } } if (old_sigpipe) (void) notify_set_signal_func((Notify_client)folio, old_sigpipe, SIGPIPE, NOTIFY_ASYNC);NoFilterReturn: (void) close(filter_input); /* ECD fix */ (void) close(filter_output); /* ECD fix */ if (selection.type & EV_SEL_PENDING_DELETE) textsw_remove_mark_internal(folio, save_lpo_id); /* Complete the deferred display update and autoscroll. */ ev_set(0, folio->views, EV_CHAIN_DELAY_UPDATE, FALSE, 0); ev_update_chain_display(folio->views); textsw_do_insert_makes_visible(view); if (save_insert) { ev_scroll_if_old_insert_visible(folio->views, textsw_find_mark_internal(folio, save_insert), /* Assign delta to minimum to ensure correct behavior, * may not be optimal. */ 1); textsw_remove_mark_internal(folio, save_insert); } return(result);ErrorReturn: result = 2; goto NormalReturn;}static inttalk_to_filter(view, filter_input, filter_output, first, last_plus_one, interpret_reply) register Textsw_view view; int filter_input, filter_output; register Es_index first, last_plus_one; int (*interpret_reply)();{#define NR_FIRST 0#define NR_LAST_PLUS_ONE 1 extern Es_index ev_get_insert(); register Textsw_folio folio = FOLIO_FOR_VIEW(view); int max_fds = GETDTABLESIZE(), nr_valid = 0, status, result = 0; unsigned long buffer_and_slop[(PIPSIZ+SLOP_SIZE)/ sizeof(unsigned long)]; unsigned char *buffer; struct timeval tv; Es_index insert, next_request[2]; /* buffer_and_slop is declared unsigned long in order to meet the * most restrictive of the alignment restrictions. */ buffer = (unsigned char *)LINT_CAST(buffer_and_slop) + SLOP_SIZE; /* * Copy data into the filter. As filter makes the filtered * data available, copy it to output_file. * Stdio is not used to read from the filter because it is necessary * to make sure that the read does not block. In addition, for both * reading and writing of the filter, the stdio automatic buffering * is only a hinderance. */ for (;;) { register int nfds; fd_set exceptfds, readfds, writefds; long int written[3]; FD_ZERO(&exceptfds); FD_ZERO(&readfds); FD_ZERO(&writefds); FD_SET(filter_output, &readfds); if (first < last_plus_one) { /* writefds |= (1 << filter_input); */ FD_SET(filter_input, &writefds); } else { /* For a "dumb" filter, we must close the input so that it * does not hang waiting for more of the selection from us. */ if (interpret_reply == interpret_filter_reply) { (void) close(filter_input); filter_input = -1; } } /* Filter only has tv.tv_sec seconds to reply, or we assume it * is permanently hung. * BUG ALERT! This should be customizable by user and/or client. */ tv.tv_sec = 15; tv.tv_usec = 0; nfds = select(max_fds, &readfds, &writefds, &exceptfds, &tv); switch (nfds) { case -1: if (errno == EINTR) continue; /* Probably itimer expired */ goto ErrorReturn; case 0: goto ErrorReturn; /* Assume filter has hung */ default: break; } /* if (readfds & (1 << filter_output)) { */ if (FD_ISSET(filter_output, &readfds)) { register int bytes_read; bytes_read = read(filter_output, (char *)buffer, sizeof(buffer_and_slop)-SLOP_SIZE); switch (bytes_read) { case 0: if (first >= last_plus_one) goto NormalReturn; break; case -1: if (errno == EINTR) break; /* Probably itimer expired */ goto ErrorReturn; default: insert = ev_get_insert(folio->views); status = interpret_reply(view, buffer, bytes_read, &written[0]); switch (status) { case REPLY_ERROR: goto ErrorReturn; case REPLY_OKAY: break; case REPLY_SEND: if AN_ERROR(nr_valid != 0) { } else { nr_valid = 1; next_request[NR_FIRST] = written[1]; next_request[NR_LAST_PLUS_ONE] = written[2]; } break; } if (insert <= first) { first += written[0]; last_plus_one += written[0]; } break; } } /* if (writefds & (1 << filter_input)) { */ if (FD_ISSET(filter_input, &writefds)) { int to_write; Es_index next; (void) es_set_position(folio->views->esh, first); to_write = sizeof(buffer_and_slop) - SLOP_SIZE; if (to_write > last_plus_one-first) to_write = last_plus_one-first; next = es_read(folio->views->esh, to_write, buffer, &to_write); if (READ_AT_EOF(first, next, to_write)) { first = last_plus_one; } else { ASSUME(to_write <= PIPSIZ); written[0] = write(filter_input, (char *)buffer, to_write); if (written[0] == -1) { if (errno == EWOULDBLOCK) { /* Go around and wait for filter to run */ } else goto ErrorReturn; } else { if (written[0] < to_write) next = (first + written[0]); first = next; } } } if (first >= last_plus_one) { if (nr_valid != 0) { first = next_request[NR_FIRST]; last_plus_one = next_request[NR_LAST_PLUS_ONE]; nr_valid = 0; } } }NormalReturn: if (filter_input != -1) (void) close(filter_input); return(result);ErrorReturn: result = 1; goto NormalReturn;#undef NR_FIRST#undef NR_LAST_PLUS_ONE}static intsmarter_interpret_filter_reply(view, buffer, buffer_length, delta) Textsw_view view; register char *buffer; int buffer_length; Es_index *delta;{ register Textsw_folio folio = FOLIO_FOR_VIEW(view); char *save_buffer = buffer; register char *buffer_last_plus_one; int *int_buffer; int result = REPLY_OKAY; /* First deal with old stuff that is left over */ if (folio->owed_by_filter < 0) { bcopy(buffer, buffer-SLOP_SIZE-folio->owed_by_filter, buffer_length); buffer_length -= folio->owed_by_filter; buffer -= SLOP_SIZE; folio->owed_by_filter = 0; } buffer_last_plus_one = buffer + buffer_length; /* Process the requests from the filter */ while (buffer < buffer_last_plus_one) { if (folio->owed_by_filter > 0) { int to_insert = folio->owed_by_filter; if (to_insert > buffer_last_plus_one-buffer) to_insert = buffer_last_plus_one-buffer; *delta = textsw_do_input(view, buffer, (long)to_insert, TXTSW_UPDATE_SCROLLBAR_IF_NEEDED); if AN_ERROR(*delta != to_insert) return(REPLY_ERROR); folio->owed_by_filter -= to_insert; buffer += ((to_insert+sizeof(int)-1)/sizeof(int))*sizeof(int); continue; } int_buffer = (int *)LINT_CAST(buffer); if ((buffer_last_plus_one-buffer < 2*sizeof(int)) || ((int_buffer[0]) != TEXTSW_FILTER_MAGIC)) goto Deal_With_Slop; switch ((Textsw_filter_command)(int_buffer[1])) { case TEXTSW_FILTER_DELETE_RANGE: if (buffer_last_plus_one-buffer < 4*sizeof(int)) goto Deal_With_Slop; *delta = textsw_delete_span(view, (long)int_buffer[2], (long)int_buffer[3], TXTSW_DS_ADJUST|TXTSW_DS_SHELVE); buffer += 4*sizeof(int); break; case TEXTSW_FILTER_INSERT: if (buffer_last_plus_one-buffer < 3*sizeof(int)) goto Deal_With_Slop; folio->owed_by_filter = int_buffer[2]; buffer += 3*sizeof(int); break; case TEXTSW_FILTER_SEND_RANGE: { if (buffer_last_plus_one-buffer < 4*sizeof(int)) goto Deal_With_Slop; delta[1] = int_buffer[2]; delta[2] = int_buffer[3]; result = REPLY_SEND; buffer += 4*sizeof(int); break; } case TEXTSW_FILTER_SET_INSERTION: if (buffer_last_plus_one-buffer < 3*sizeof(int)) goto Deal_With_Slop; (void) ev_set_insert(folio->views, (Es_index)int_buffer[2]); buffer += 3*sizeof(int); break; case TEXTSW_FILTER_SET_SELECTION: if (buffer_last_plus_one-buffer < 4*sizeof(int))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -