URI: 
       main.c - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       main.c (4447B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 #include <bio.h>
            4 #include "diff.h"
            5 
            6 #define        DIRECTORY(s)                ((s)->qid.type&QTDIR)
            7 #define        REGULAR_FILE(s)                ((s)->type == 'M' && !DIRECTORY(s))
            8 
            9 Biobuf        stdout;
           10 
           11 static char *tmp[] = {"/tmp/diff1XXXXXXXXXXX", "/tmp/diff2XXXXXXXXXXX"};
           12 static int whichtmp;
           13 static char *progname;
           14 static char usage[] = "diff [ -acefmnbwr ] file1 ... file2\n";
           15 
           16 static void
           17 rmtmpfiles(void)
           18 {
           19         while (whichtmp > 0) {
           20                 whichtmp--;
           21                 remove(tmp[whichtmp]);
           22         }
           23 }
           24 
           25 void        
           26 done(int status)
           27 {
           28         rmtmpfiles();
           29         switch(status)
           30         {
           31         case 0:
           32                 exits("");
           33         case 1:
           34                 exits("some");
           35         default:
           36                 exits("error");
           37         }
           38         /*NOTREACHED*/
           39 }
           40 
           41 void
           42 panic(int status, char *fmt, ...)
           43 {
           44         va_list arg;
           45 
           46         Bflush(&stdout);
           47 
           48         fprint(2, "%s: ", progname);
           49         va_start(arg, fmt);
           50         vfprint(2, fmt, arg);
           51         va_end(arg);
           52         if (status)
           53                 done(status);
           54                 /*NOTREACHED*/
           55 }
           56 
           57 static int
           58 catch(void *a, char *msg)
           59 {
           60         USED(a);
           61         panic(2, msg);
           62         return 1;
           63 }
           64 
           65 int
           66 mkpathname(char *pathname, char *path, char *name)
           67 {
           68         if (strlen(path) + strlen(name) > MAXPATHLEN) {
           69                 panic(0, "pathname %s/%s too long\n", path, name);
           70                 return 1;
           71         }
           72         sprint(pathname, "%s/%s", path, name);
           73         return 0;
           74 }
           75         
           76 static char *
           77 mktmpfile(int input, Dir **sb)
           78 {
           79         int fd, i;
           80         char *p;
           81         char buf[8192];
           82 
           83         atnotify(catch, 1);
           84 /*
           85         p = mktemp(tmp[whichtmp++]);
           86         fd = create(p, OWRITE, 0600);
           87 */
           88         fd = mkstemp(p=tmp[whichtmp++]);
           89         if (fd < 0) {
           90                 panic(mflag ? 0: 2, "cannot create %s: %r\n", p);
           91                 return 0;
           92         }
           93         while ((i = read(input, buf, sizeof(buf))) > 0) {
           94                 if ((i = write(fd, buf, i)) < 0)
           95                         break;
           96         }
           97         *sb = dirfstat(fd);
           98         close(fd);
           99         if (i < 0) {
          100                 panic(mflag ? 0: 2, "cannot read/write %s: %r\n", p);
          101                 return 0;
          102         }
          103         return p;
          104 }
          105 
          106 static char *
          107 statfile(char *file, Dir **sb)
          108 {
          109         Dir *dir;
          110         int input;
          111 
          112         dir = dirstat(file);
          113         if(dir == nil) {
          114                 if (strcmp(file, "-") || (dir = dirfstat(0)) == nil) {
          115                         panic(mflag ? 0: 2, "cannot stat %s: %r\n", file);
          116                         return 0;
          117                 }
          118                 free(dir);
          119                 return mktmpfile(0, sb);
          120         }
          121         else if (!REGULAR_FILE(dir) && !DIRECTORY(dir)) {
          122                 free(dir);
          123                 if ((input = open(file, OREAD)) == -1) {
          124                         panic(mflag ? 0: 2, "cannot open %s: %r\n", file);
          125                         return 0;
          126                 }
          127                 file = mktmpfile(input, sb);
          128                 close(input);
          129         }
          130         else
          131                 *sb = dir;
          132         return file;
          133 }
          134 
          135 void
          136 diff(char *f, char *t, int level)
          137 {
          138         char *fp, *tp, *p, fb[MAXPATHLEN+1], tb[MAXPATHLEN+1];
          139         Dir *fsb, *tsb;
          140 
          141         if ((fp = statfile(f, &fsb)) == 0)
          142                 goto Return;
          143         if ((tp = statfile(t, &tsb)) == 0){
          144                 free(fsb);
          145                 goto Return;
          146         }
          147         if (DIRECTORY(fsb) && DIRECTORY(tsb)) {
          148                 if (rflag || level == 0)
          149                         diffdir(fp, tp, level);
          150                 else
          151                         Bprint(&stdout, "Common subdirectories: %s and %s\n",
          152                                 fp, tp);
          153         }
          154         else if (REGULAR_FILE(fsb) && REGULAR_FILE(tsb))
          155                 diffreg(fp, tp);
          156         else {
          157                 if (REGULAR_FILE(fsb)) {
          158                         if ((p = utfrrune(f, '/')) == 0)
          159                                 p = f;
          160                         else
          161                                 p++;
          162                         if (mkpathname(tb, tp, p) == 0)
          163                                 diffreg(fp, tb);
          164                 }
          165                 else {
          166                         if ((p = utfrrune(t, '/')) == 0)
          167                                 p = t;
          168                         else
          169                                 p++;
          170                         if (mkpathname(fb, fp, p) == 0)
          171                                 diffreg(fb, tp);
          172                 }
          173         }
          174         free(fsb);
          175         free(tsb);
          176 Return:
          177         rmtmpfiles();
          178 }
          179 
          180 void
          181 main(int argc, char *argv[])
          182 {
          183         char *p;
          184         int i;
          185         Dir *fsb, *tsb;
          186         extern int _p9usepwlibrary;
          187         
          188         _p9usepwlibrary = 0;
          189         Binit(&stdout, 1, OWRITE);
          190         progname = *argv;
          191         while (--argc && (*++argv)[0] == '-' && (*argv)[1]) {
          192                 for (p = *argv+1; *p; p++) {
          193                         switch (*p) {
          194 
          195                         case 'e':
          196                         case 'f':
          197                         case 'n':
          198                         case 'c':
          199                         case 'a':
          200                                 mode = *p;
          201                                 break;
          202 
          203                         case 'w':
          204                                 bflag = 2;
          205                                 break;
          206 
          207                         case 'b':
          208                                 bflag = 1;
          209                                 break;
          210 
          211                         case 'r':
          212                                 rflag = 1;
          213                                 mflag = 1;
          214                                 break;
          215 
          216                         case 'm':
          217                                 mflag = 1;        
          218                                 break;
          219 
          220                         case 'h':
          221                         default:
          222                                 progname = "Usage";
          223                                 panic(2, usage);
          224                         }
          225                 }
          226         }
          227         if (argc < 2)
          228                 panic(2, usage, progname);
          229         if ((tsb = dirstat(argv[argc-1])) == nil)
          230                 panic(2, "can't stat %s\n", argv[argc-1]);
          231         if (argc > 2) {
          232                 if (!DIRECTORY(tsb))
          233                         panic(2, usage, progname);
          234                 mflag = 1;
          235         }
          236         else {
          237                 if ((fsb = dirstat(argv[0])) == nil)
          238                         panic(2, "can't stat %s\n", argv[0]);
          239                 if (DIRECTORY(fsb) && DIRECTORY(tsb))
          240                         mflag = 1;
          241                 free(fsb);
          242         }
          243         free(tsb);
          244         for (i = 0; i < argc-1; i++)
          245                 diff(argv[i], argv[argc-1], 0);
          246         done(anychange);
          247         /*NOTREACHED*/
          248 }
          249 
          250 static char noroom[] = "out of memory - try diff -h\n";
          251 
          252 void *
          253 emalloc(unsigned n)
          254 {
          255         register void *p;
          256 
          257         if ((p = malloc(n)) == 0)
          258                 panic(2, noroom);
          259         return p;
          260 }
          261 
          262 void *
          263 erealloc(void *p, unsigned n)
          264 {
          265         register void *rp;
          266 
          267         if ((rp = realloc(p, n)) == 0)
          268                 panic(2, noroom);
          269         return rp;
          270 }