📄 util.c
字号:
putc ('\n', stderr); fflush (stderr); fatal_exit (0);}voidmemory_fatal (void){ fatal ("out of memory");}voidread_fatal (void){ pfatal ("read error");}voidwrite_fatal (void){ pfatal ("write error");}/* Say something from patch, something from the system, then silence . . . */voidpfatal (char const *format, ...){ int errnum = errno; va_list args; fprintf (stderr, "%s: **** ", program_name); va_start (args, format); vfprintf (stderr, format, args); va_end (args); fflush (stderr); /* perror bypasses stdio on some hosts. */ errno = errnum; perror (" "); fflush (stderr); fatal_exit (0);}/* Tell the user something. */voidsay (char const *format, ...){ va_list args; va_start (args, format); vfprintf (stdout, format, args); va_end (args); fflush (stdout);}/* Get a response from the user, somehow or other. */voidask (char const *format, ...){ static int ttyfd = -2; int r; va_list args; va_start (args, format); vfprintf (stdout, format, args); va_end (args); fflush (stdout); if (ttyfd == -2) { /* If standard output is not a tty, don't bother opening /dev/tty, since it's unlikely that stdout will be seen by the tty user. The isatty test also works around a bug in GNU Emacs 19.34 under Linux which makes a call-process `patch' hang when it reads from /dev/tty. POSIX.1-2001 XCU line 26599 requires that we read /dev/tty, though. */ ttyfd = (posixly_correct || isatty (STDOUT_FILENO) ? open (TTY_DEVICE, O_RDONLY) : -1); } if (ttyfd < 0) { /* No terminal at all -- default it. */ printf ("\n"); buf[0] = '\n'; buf[1] = '\0'; } else { size_t s = 0; while ((r = read (ttyfd, buf + s, bufsize - 1 - s)) == bufsize - 1 - s && buf[bufsize - 2] != '\n') { s = bufsize - 1; bufsize *= 2; buf = realloc (buf, bufsize); if (!buf) memory_fatal (); } if (r == 0) printf ("EOF\n"); else if (r < 0) { perror ("tty read"); fflush (stderr); close (ttyfd); ttyfd = -1; r = 0; } buf[s + r] = '\0'; }}/* Return nonzero if it OK to reverse a patch. */boolok_to_reverse (char const *format, ...){ bool r = false; if (noreverse || ! (force && verbosity == SILENT)) { va_list args; va_start (args, format); vfprintf (stdout, format, args); va_end (args); } if (noreverse) { printf (" Skipping patch.\n"); skip_rest_of_patch = true; } else if (force) { if (verbosity != SILENT) printf (" Applying it anyway.\n"); } else if (batch) { say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n"); r = true; } else { ask (reverse ? " Ignore -R? [n] " : " Assume -R? [n] "); r = *buf == 'y'; if (! r) { ask ("Apply anyway? [n] "); if (*buf != 'y') { if (verbosity != SILENT) say ("Skipping patch.\n"); skip_rest_of_patch = true; } } } return r;}/* How to handle certain events when not in a critical region. */#define NUM_SIGS (sizeof (sigs) / sizeof (*sigs))static int const sigs[] = {#ifdef SIGHUP SIGHUP,#endif#ifdef SIGPIPE SIGPIPE,#endif#ifdef SIGTERM SIGTERM,#endif#ifdef SIGXCPU SIGXCPU,#endif#ifdef SIGXFSZ SIGXFSZ,#endif SIGINT};#if !HAVE_SIGPROCMASK#define sigset_t int#define sigemptyset(s) (*(s) = 0)#ifndef sigmask#define sigmask(sig) (1 << ((sig) - 1))#endif#define sigaddset(s, sig) (*(s) |= sigmask (sig))#define sigismember(s, sig) ((*(s) & sigmask (sig)) != 0)#ifndef SIG_BLOCK#define SIG_BLOCK 0#endif#ifndef SIG_UNBLOCK#define SIG_UNBLOCK (SIG_BLOCK + 1)#endif#ifndef SIG_SETMASK#define SIG_SETMASK (SIG_BLOCK + 2)#endif#define sigprocmask(how, n, o) \ ((how) == SIG_BLOCK \ ? ((o) ? *(o) = sigblock (*(n)) : sigblock (*(n))) \ : (how) == SIG_UNBLOCK \ ? sigsetmask (((o) ? *(o) = sigblock (0) : sigblock (0)) & ~*(n)) \ : (o ? *(o) = sigsetmask (*(n)) : sigsetmask (*(n))))#if !HAVE_SIGSETMASK#define sigblock(mask) 0#define sigsetmask(mask) 0#endif#endifstatic sigset_t initial_signal_mask;static sigset_t signals_to_block;#if ! HAVE_SIGACTIONstatic RETSIGTYPE fatal_exit_handler (int) __attribute__ ((noreturn));static RETSIGTYPEfatal_exit_handler (int sig){ signal (sig, SIG_IGN); fatal_exit (sig);}#endifvoidset_signals (bool reset){ int i;#if HAVE_SIGACTION struct sigaction initial_act, fatal_act; fatal_act.sa_handler = fatal_exit; sigemptyset (&fatal_act.sa_mask); fatal_act.sa_flags = 0;#define setup_handler(sig) sigaction (sig, &fatal_act, (struct sigaction *) 0)#else#define setup_handler(sig) signal (sig, fatal_exit_handler)#endif if (!reset) {#ifdef SIGCHLD /* System V fork+wait does not work if SIGCHLD is ignored. */ signal (SIGCHLD, SIG_DFL);#endif sigemptyset (&signals_to_block); for (i = 0; i < NUM_SIGS; i++) { bool ignoring_signal;#if HAVE_SIGACTION if (sigaction (sigs[i], (struct sigaction *) 0, &initial_act) != 0) continue; ignoring_signal = initial_act.sa_handler == SIG_IGN;#else ignoring_signal = signal (sigs[i], SIG_IGN) == SIG_IGN;#endif if (! ignoring_signal) { sigaddset (&signals_to_block, sigs[i]); setup_handler (sigs[i]); } } } else { /* Undo the effect of ignore_signals. */#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK sigprocmask (SIG_SETMASK, &initial_signal_mask, (sigset_t *) 0);#else for (i = 0; i < NUM_SIGS; i++) if (sigismember (&signals_to_block, sigs[i])) setup_handler (sigs[i]);#endif }}/* How to handle certain events when in a critical region. */voidignore_signals (void){#if HAVE_SIGPROCMASK || HAVE_SIGSETMASK sigprocmask (SIG_BLOCK, &signals_to_block, &initial_signal_mask);#else int i; for (i = 0; i < NUM_SIGS; i++) if (sigismember (&signals_to_block, sigs[i])) signal (sigs[i], SIG_IGN);#endif}voidexit_with_signal (int sig){ sigset_t s; signal (sig, SIG_DFL); sigemptyset (&s); sigaddset (&s, sig); sigprocmask (SIG_UNBLOCK, &s, (sigset_t *) 0); raise (sig); exit (2);}intsystemic (char const *command){ if (debug & 8) say ("+ %s\n", command); fflush (stdout); return system (command);}/* Replace '/' with '\0' in FILENAME if it marks a place that needs testing for the existence of directory. Return the address of the last location replaced, or 0 if none were replaced. */static char *replace_slashes (char *filename){ char *f; char *last_location_replaced = 0; char const *component_start; for (f = filename + FILESYSTEM_PREFIX_LEN (filename); ISSLASH (*f); f++) continue; component_start = f; for (; *f; f++) if (ISSLASH (*f)) { char *slash = f; /* Treat multiple slashes as if they were one slash. */ while (ISSLASH (f[1])) f++; /* Ignore slashes at the end of the path. */ if (! f[1]) break; /* "." and ".." need not be tested. */ if (! (slash - component_start <= 2 && component_start[0] == '.' && slash[-1] == '.')) { *slash = '\0'; last_location_replaced = slash; } component_start = f + 1; } return last_location_replaced;}/* Make sure we'll have the directories to create a file. Ignore the last element of `filename'. */static voidmakedirs (register char *filename){ register char *f; register char *flim = replace_slashes (filename); if (flim) { /* Create any missing directories, replacing NULs by '/'s. Ignore errors. We may have to keep going even after an EEXIST, since the path may contain ".."s; and when there is an EEXIST failure the system may return some other error number. Any problems will eventually be reported when we create the file. */ for (f = filename; f <= flim; f++) if (!*f) { mkdir (filename, S_IRUSR|S_IWUSR|S_IXUSR |S_IRGRP|S_IWGRP|S_IXGRP |S_IROTH|S_IWOTH|S_IXOTH); *f = '/'; } }}/* Remove empty ancestor directories of FILENAME. Ignore errors, since the path may contain ".."s, and when there is an EEXIST failure the system may return some other error number. */voidremovedirs (char *filename){ size_t i; for (i = strlen (filename); i != 0; i--) if (ISSLASH (filename[i]) && ! (ISSLASH (filename[i - 1]) || (filename[i - 1] == '.' && (i == 1 || ISSLASH (filename[i - 2]) || (filename[i - 2] == '.' && (i == 2 || ISSLASH (filename[i - 3]))))))) { filename[i] = '\0'; if (rmdir (filename) == 0 && verbosity == VERBOSE) say ("Removed empty directory %s\n", quotearg (filename)); filename[i] = '/'; }}static time_t initial_time;voidinit_time (void){ time (&initial_time);}/* Make filenames more reasonable. */char *fetchname (char *at, int strip_leading, time_t *pstamp){ char *name; register char *t; int sleading = strip_leading; time_t stamp = (time_t) -1; while (ISSPACE ((unsigned char) *at)) at++; if (debug & 128) say ("fetchname %s %d\n", at, strip_leading); name = at; /* Strip up to `strip_leading' leading slashes and null terminate. If `strip_leading' is negative, strip all leading slashes. */ for (t = at; *t; t++) { if (ISSLASH (*t)) { while (ISSLASH (t[1])) t++; if (strip_leading < 0 || --sleading >= 0) name = t+1; } else if (ISSPACE ((unsigned char) *t)) { /* Allow file names with internal spaces, but only if a tab separates the file name from the date. */ char const *u = t; while (*u != '\t' && ISSPACE ((unsigned char) u[1])) u++; if (*u != '\t' && strchr (u + 1, '\t')) continue; if (set_time | set_utc) stamp = str2time (&u, initial_time, set_utc ? 0L : TM_LOCAL_ZONE); else { /* The head says the file is nonexistent if the timestamp is the epoch; but the listed time is local time, not UTC, and POSIX.1 allows local time offset anywhere in the range -25:00 < offset < +26:00. Match any time in that range by assuming local time is -25:00 and then matching any ``local'' time T in the range 0 < T < 25+26 hours. */ stamp = str2time (&u, initial_time, -25L * 60 * 60); if (0 < stamp && stamp < (25 + 26) * 60L * 60) stamp = 0; } if (*u && ! ISSPACE ((unsigned char) *u)) stamp = (time_t) -1; *t = '\0'; break; } } if (!*name) return 0; /* If the name is "/dev/null", ignore the name and mark the file as being nonexistent. The name "/dev/null" appears in patches regardless of how NULL_DEVICE is spelled. */ if (strcmp (at, "/dev/null") == 0) { if (pstamp) *pstamp = 0; return 0; } /* Ignore the name if it doesn't have enough slashes to strip off. */ if (0 < sleading) return 0; if (pstamp) *pstamp = stamp; return savestr (name);}voidFseek (FILE *stream, file_offset offset, int ptrname){ if (file_seek (stream, offset, ptrname) != 0) pfatal ("fseek");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -