1 #include "EXTERN.h" 2 #include "common.h" 3 #include "INTERN.h" 4 #include "util.h" 5 6 /* Rename a file, copying it if necessary. */ 7 8 int 9 move_file(from,to) 10 char *from, *to; 11 { 12 char bakname[512]; 13 Reg1 char *s; 14 Reg2 int i; 15 Reg3 int fromfd; 16 17 /* to stdout? */ 18 19 if (strEQ(to, "-")) { 20 #ifdef DEBUGGING 21 if (debug & 4) 22 say2("Moving %s to stdout.\n", from); 23 #endif 24 fromfd = open(from, 0); 25 if (fromfd < 0) 26 fatal2("patch: internal error, can't reopen %s\n", from); 27 while ((i=read(fromfd, buf, sizeof buf)) > 0) 28 if (write(1, buf, i) != 1) 29 fatal1("patch: write failed\n"); 30 Close(fromfd); 31 return 0; 32 } 33 34 Strcpy(bakname, to); 35 Strcat(bakname, origext?origext:ORIGEXT); 36 if (stat(to, &filestat) >= 0) { /* output file exists */ 37 dev_t to_device = filestat.st_dev; 38 ino_t to_inode = filestat.st_ino; 39 char *simplename = bakname; 40 41 for (s=bakname; *s; s++) { 42 if (*s == '/') 43 simplename = s+1; 44 } 45 /* find a backup name that is not the same file */ 46 while (stat(bakname, &filestat) >= 0 && 47 to_device == filestat.st_dev && to_inode == filestat.st_ino) { 48 for (s=simplename; *s && !islower(*s); s++) ; 49 if (*s) 50 *s = toupper(*s); 51 else 52 Strcpy(simplename, simplename+1); 53 } 54 while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */ 55 #ifdef DEBUGGING 56 if (debug & 4) 57 say3("Moving %s to %s.\n", to, bakname); 58 #endif 59 if (link(to, bakname) < 0) { 60 say3("patch: can't backup %s, output is in %s\n", 61 to, from); 62 return -1; 63 } 64 while (unlink(to) >= 0) ; 65 } 66 #ifdef DEBUGGING 67 if (debug & 4) 68 say3("Moving %s to %s.\n", from, to); 69 #endif 70 if (link(from, to) < 0) { /* different file system? */ 71 Reg4 int tofd; 72 73 tofd = creat(to, 0666); 74 if (tofd < 0) { 75 say3("patch: can't create %s, output is in %s.\n", 76 to, from); 77 return -1; 78 } 79 fromfd = open(from, 0); 80 if (fromfd < 0) 81 fatal2("patch: internal error, can't reopen %s\n", from); 82 while ((i=read(fromfd, buf, sizeof buf)) > 0) 83 if (write(tofd, buf, i) != i) 84 fatal1("patch: write failed\n"); 85 Close(fromfd); 86 Close(tofd); 87 } 88 Unlink(from); 89 return 0; 90 } 91 92 /* Copy a file. */ 93 94 void 95 copy_file(from,to) 96 char *from, *to; 97 { 98 Reg3 int tofd; 99 Reg2 int fromfd; 100 Reg1 int i; 101 102 tofd = creat(to, 0666); 103 if (tofd < 0) 104 fatal2("patch: can't create %s.\n", to); 105 fromfd = open(from, 0); 106 if (fromfd < 0) 107 fatal2("patch: internal error, can't reopen %s\n", from); 108 while ((i=read(fromfd, buf, sizeof buf)) > 0) 109 if (write(tofd, buf, i) != i) 110 fatal2("patch: write (%s) failed\n", to); 111 Close(fromfd); 112 Close(tofd); 113 } 114 115 /* Allocate a unique area for a string. */ 116 117 char * 118 savestr(s) 119 Reg1 char *s; 120 { 121 Reg3 char *rv; 122 Reg2 char *t; 123 124 if (!s) 125 s = "Oops"; 126 t = s; 127 while (*t++); 128 rv = malloc((MEM) (t - s)); 129 if (rv == Nullch) { 130 if (using_plan_a) 131 out_of_mem = TRUE; 132 else 133 fatal1("patch: out of memory (savestr)\n"); 134 } 135 else { 136 t = rv; 137 while (*t++ = *s++); 138 } 139 return rv; 140 } 141 142 #if defined(lint) && defined(CANVARARG) 143 144 /*VARARGS ARGSUSED*/ 145 say(pat) char *pat; { ; } 146 /*VARARGS ARGSUSED*/ 147 fatal(pat) char *pat; { ; } 148 /*VARARGS ARGSUSED*/ 149 ask(pat) char *pat; { ; } 150 151 #else 152 153 /* Vanilla terminal output (buffered). */ 154 155 void 156 say(pat,arg1,arg2,arg3) 157 char *pat; 158 int arg1,arg2,arg3; 159 { 160 fprintf(stderr, pat, arg1, arg2, arg3); 161 Fflush(stderr); 162 } 163 164 /* Terminal output, pun intended. */ 165 166 void /* very void */ 167 fatal(pat,arg1,arg2,arg3) 168 char *pat; 169 int arg1,arg2,arg3; 170 { 171 void my_exit(); 172 173 say(pat, arg1, arg2, arg3); 174 my_exit(1); 175 } 176 177 /* Get a response from the user, somehow or other. */ 178 179 void 180 ask(pat,arg1,arg2,arg3) 181 char *pat; 182 int arg1,arg2,arg3; 183 { 184 int ttyfd; 185 int r; 186 bool tty2 = isatty(2); 187 188 Sprintf(buf, pat, arg1, arg2, arg3); 189 Fflush(stderr); 190 write(2, buf, strlen(buf)); 191 if (tty2) { /* might be redirected to a file */ 192 r = read(2, buf, sizeof buf); 193 } 194 else if (isatty(1)) { /* this may be new file output */ 195 Fflush(stdout); 196 write(1, buf, strlen(buf)); 197 r = read(1, buf, sizeof buf); 198 } 199 else if ((ttyfd = open("/dev/tty", 2)) >= 0 && isatty(ttyfd)) { 200 /* might be deleted or unwriteable */ 201 write(ttyfd, buf, strlen(buf)); 202 r = read(ttyfd, buf, sizeof buf); 203 Close(ttyfd); 204 } 205 else if (isatty(0)) { /* this is probably patch input */ 206 Fflush(stdin); 207 write(0, buf, strlen(buf)); 208 r = read(0, buf, sizeof buf); 209 } 210 else { /* no terminal at all--default it */ 211 buf[0] = '\n'; 212 r = 1; 213 } 214 if (r <= 0) 215 buf[0] = 0; 216 else 217 buf[r] = '\0'; 218 if (!tty2) 219 say1(buf); 220 } 221 #endif lint 222 223 /* How to handle certain events when not in a critical region. */ 224 225 void 226 set_signals() 227 { 228 void my_exit(); 229 230 #ifndef lint 231 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) 232 Signal(SIGHUP, my_exit); 233 if (signal(SIGINT, SIG_IGN) != SIG_IGN) 234 Signal(SIGINT, my_exit); 235 #endif 236 } 237 238 /* How to handle certain events when in a critical region. */ 239 240 void 241 ignore_signals() 242 { 243 #ifndef lint 244 Signal(SIGHUP, SIG_IGN); 245 Signal(SIGINT, SIG_IGN); 246 #endif 247 } 248 249 /* Make sure we'll have the directories to create a file. */ 250 251 void 252 makedirs(filename,striplast) 253 Reg1 char *filename; 254 bool striplast; 255 { 256 char tmpbuf[256]; 257 Reg2 char *s = tmpbuf; 258 char *dirv[20]; 259 Reg3 int i; 260 Reg4 int dirvp = 0; 261 262 while (*filename) { 263 if (*filename == '/') { 264 filename++; 265 dirv[dirvp++] = s; 266 *s++ = '\0'; 267 } 268 else { 269 *s++ = *filename++; 270 } 271 } 272 *s = '\0'; 273 dirv[dirvp] = s; 274 if (striplast) 275 dirvp--; 276 if (dirvp < 0) 277 return; 278 strcpy(buf, "mkdir"); 279 s = buf; 280 for (i=0; i<=dirvp; i++) { 281 while (*s) s++; 282 *s++ = ' '; 283 strcpy(s, tmpbuf); 284 *dirv[i] = '/'; 285 } 286 system(buf); 287 } 288 289 /* Make filenames more reasonable. */ 290 291 char * 292 fetchname(at,strip_leading,assume_exists) 293 char *at; 294 int strip_leading; 295 int assume_exists; 296 { 297 char *s; 298 char *name; 299 Reg1 char *t; 300 char tmpbuf[200]; 301 302 if (!at) 303 return Nullch; 304 s = savestr(at); 305 for (t=s; isspace(*t); t++) ; 306 name = t; 307 #ifdef DEBUGGING 308 if (debug & 128) 309 say4("fetchname %s %d %d\n",name,strip_leading,assume_exists); 310 #endif 311 if (strnEQ(name, "/dev/null", 9)) /* so files can be created by diffing */ 312 return Nullch; /* against /dev/null. */ 313 for (; *t && !isspace(*t); t++) 314 if (*t == '/') 315 if (--strip_leading >= 0) 316 name = t+1; 317 *t = '\0'; 318 if (name != s && *s != '/') { 319 name[-1] = '\0'; 320 if (stat(s, &filestat) && filestat.st_mode & S_IFDIR) { 321 name[-1] = '/'; 322 name=s; 323 } 324 } 325 name = savestr(name); 326 Sprintf(tmpbuf, "RCS/%s", name); 327 free(s); 328 if (stat(name, &filestat) < 0 && !assume_exists) { 329 Strcat(tmpbuf, RCSSUFFIX); 330 if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+4, &filestat) < 0) { 331 Sprintf(tmpbuf, "SCCS/%s%s", SCCSPREFIX, name); 332 if (stat(tmpbuf, &filestat) < 0 && stat(tmpbuf+5, &filestat) < 0) { 333 free(name); 334 name = Nullch; 335 } 336 } 337 } 338 return name; 339 } 340