util.c
来自「这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易」· C语言 代码 · 共 1,080 行 · 第 1/2 页
C
1,080 行
#else/*VARARGS1*/ voidsay (format, va_alist) char const *format; va_dcl#endif{ va_list args; vararg_start (args, format); vfprintf (stdout, format, args); va_end (args); fflush (stdout);}/* Get a response from the user, somehow or other. */#ifdef __STDC__voidask (char const *format, ...)#else/*VARARGS1*/ voidask (format, va_alist) char const *format; va_dcl#endif{ static int ttyfd = -2; int r; va_list args; vararg_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.2 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. */#ifdef __STDC__intok_to_reverse (char const *format, ...)#elseok_to_reverse (format, va_alist) char const *format; va_dcl#endif{ int r = 0; if (noreverse || ! (force && verbosity == SILENT)) { va_list args; vararg_start (args, format); vfprintf (stdout, format, args); va_end (args); } if (noreverse) { printf (" Skipping patch.\n"); skip_rest_of_patch = TRUE; r = 0; } else if (force) { if (verbosity != SILENT) printf (" Applying it anyway.\n"); r = 0; } else if (batch) { say (reverse ? " Ignoring -R.\n" : " Assuming -R.\n"); r = 1; } 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 PARAMS ((int)) __attribute__ ((noreturn));static RETSIGTYPEfatal_exit_handler (sig) int sig;{ signal (sig, SIG_IGN); fatal_exit (sig);}#endifvoidset_signals(reset)int 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++) { int 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(){#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 (sig) 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 (command) char const *command;{ if (debug & 8) say ("+ %s\n", command); fflush (stdout); return system (command);}#if !HAVE_MKDIR/* These mkdir and rmdir substitutes are good enough for `patch'; they are not general emulators. */static int doprogram PARAMS ((char const *, char const *));static int mkdir PARAMS ((char const *, mode_t));static int rmdir PARAMS ((char const *));static intdoprogram (program, arg) char const *program; char const *arg;{ int result; static char const DISCARD_OUTPUT[] = " 2>/dev/null"; size_t program_len = strlen (program); char *cmd = xmalloc (program_len + 1 + quote_system_arg (0, arg) + sizeof DISCARD_OUTPUT); char *p = cmd; strcpy (p, program); p += program_len; *p++ = ' '; p += quote_system_arg (p, arg); strcpy (p, DISCARD_OUTPUT); result = systemic (cmd); free (cmd); return result;}#ifdef __STDC__/* If mode_t doesn't promote to itself, we can't use old-style definition. */static intmkdir (char const *path, mode_t mode)#elsestatic intmkdir (path, mode) char const *path; mode_t mode; /* ignored */#endif{ return doprogram ("mkdir", path);}static intrmdir (path) char const *path;{ int result = doprogram ("rmdir", path); errno = EEXIST; return result;}#endif/* 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 PARAMS ((char *));static char *replace_slashes (filename) 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 (filename) 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 (filename) 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", filename); filename[i] = '/'; }}static time_t initial_time;voidinit_time (){ time (&initial_time);}/* Make filenames more reasonable. */char *fetchname (at, strip_leading, pstamp)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 off up to `sleading' leading slashes and null terminate. */ for (t = at; *t; t++) { if (ISSLASH (*t)) { while (ISSLASH (t[1])) t++; if (--sleading >= 0) name = t+1; } else if (ISSPACE ((unsigned char) *t)) { if (set_time | set_utc) stamp = str2time (t, 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 to be 24 hours away from UTC. So match any time within 24 hours of the epoch. Use a default time zone 24 hours behind UTC so that any non-zoned time within 24 hours of the epoch is valid. */ stamp = str2time (t, initial_time, -24L * 60 * 60); if (0 <= stamp && stamp <= 2 * 24L * 60 * 60) stamp = 0; } *t = '\0'; break; } } if (!*name) return 0; /* Allow files to be created by diffing against /dev/null. */ if (strcmp (at, "/dev/null") == 0) { if (pstamp) *pstamp = 0; return 0; } if (pstamp) *pstamp = stamp; return savestr (name);}GENERIC_OBJECT *xmalloc (size) size_t size;{ register GENERIC_OBJECT *p = malloc (size); if (!p) memory_fatal (); return p;}voidFseek (stream, offset, ptrname) FILE *stream; file_offset offset; int ptrname;{ if (file_seek (stream, offset, ptrname) != 0) pfatal ("fseek");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?