Some questions about porting code from C to BetterC

Bagomot bagomot at gmail.com
Tue Nov 30 21:05:46 UTC 2021


I wonder what you have to say about this code. It's almost 
finished, but there are a number of problems - all functions 
work, except for calling redo with an empty argument. The reasons 
for some errors are not clear to me. Write if you have comments 
or ideas.
```d
import core.stdc.stdio;

version (Posix)
{
     extern (C)
     {
		import core.stdc.errno : errno, EAGAIN, ECHILD;
		import core.stdc.inttypes : PRIx64;
		import core.stdc.limits: PATH_MAX;
		import core.stdc.stdarg;
		import core.stdc.stdio;
		import core.stdc.stdlib : malloc, exit, getenv, strtol;
		import core.stdc.string : memcpy, memset, strchr, strcmp, 
strncpy, strdup, strlen, strncmp, strrchr;
		
         import core.sys.posix.fcntl;
         import core.sys.posix.sys.stat;
         import core.sys.posix.sys.types : off_t, ssize_t;
         import core.sys.posix.unistd;
         import core.sys.posix.sys.wait : waitpid, WNOHANG;

         int access(const char* pathname, int mode);
         int close(int fd);
         int dprintf(int fd, scope const char* format, ...) 
nothrow @nogc;
         int mkstemp(scope const(char*) tmplt) nothrow @nogc;
         int openat(int dirfd, scope const(char*) pathname, int 
flags) nothrow @nogc;
         ssize_t pread(int fd, void* buf, size_t count, off_t 
offset) @nogc;
         int setenv(scope const(char*) name, scope const(char*) 
value, int overwrite);

         int printf (scope const(char*) format, ...) nothrow @nogc;

         version(X86_64)
         {
			// from <fcntl.h>
			enum O_DIRECTORY = 0x10000;
		}
		
		extern (D) int __WTERMSIG( int status ) { return status & 0x7F; 
}
		extern (D) int  WEXITSTATUS( int status )  { return ( status & 
0xFF00 ) >> 8;   }
		extern (D) bool WIFEXITED( int status )    { return __WTERMSIG( 
status ) == 0;  }

		struct sha256
		{
			ulong len;
			uint[8] h;
			ubyte[64] buf;
		}
		
		uint ror(uint n, int k) pure nothrow @nogc
         {
             return (n >> k) | (n << (32 - k));
         }

         uint Ch(uint x, uint y, uint z) pure nothrow @nogc
         {
             return (z ^ (x & (y ^ z)));
         }

         uint Maj(uint x, uint y, uint z) pure nothrow @nogc
         {
             return ((x & y) | (z & (x | y)));
         }

         uint S0(uint x) pure nothrow @nogc
         {
             return (ror(x, 2) ^ ror(x, 13) ^ ror(x, 22));
         }

         uint S1(uint x) pure nothrow @nogc
         {
             return (ror(x, 6) ^ ror(x, 11) ^ ror(x, 25));
         }

         uint R0(uint x) pure nothrow @nogc
         {
             return (ror(x, 7) ^ ror(x, 18) ^ (x >> 3));
         }

         uint R1(uint x) pure nothrow @nogc
         {
             return (ror(x, 17) ^ ror(x, 19) ^ (x >> 10));
         }
		
		static const uint[64] K = [
			0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 
0x59f111f1, 0x923f82a4, 0xab1c5ed5,
			0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 
0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
			0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 
0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
			0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 
0xd5a79147, 0x06ca6351, 0x14292967,
			0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 
0x766a0abb, 0x81c2c92e, 0x92722c85,
			0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 
0xd6990624, 0xf40e3585, 0x106aa070,
			0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 
0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
			0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 
0xa4506ceb, 0xbef9a3f7, 0xc67178f2
		];
		
		static void processblock(sha256* s, const(ubyte*) buf)
		{
			uint[64] W;
			uint t1, t2, a, b, c, d, e, f, g, h;
			int i;
		
			for (i = 0; i < 16; i++)
			{
				W[i]  = cast(uint) buf[4*i]<<24;
				W[i] |= cast(uint) buf[4*i+1]<<16;
				W[i] |= cast(uint) buf[4*i+2]<<8;
				W[i] |= buf[4*i+3];
			}
			
			for (; i < 64; i++)
			{
				W[i] = R1(W[i-2]) + W[i-7] + R0(W[i-15]) + W[i-16];
			}
			
			a = s.h[0];
			b = s.h[1];
			c = s.h[2];
			d = s.h[3];
			e = s.h[4];
			f = s.h[5];
			g = s.h[6];
			h = s.h[7];
			
			for (i = 0; i < 64; i++)
			{
				t1 = h + S1(e) + Ch(e, f, g) + K[i] + W[i];
				t2 = S0(a) + Maj(a, b, c);
				h = g;
				g = f;
				f = e;
				e = d + t1;
				d = c;
				c = b;
				b = a;
				a = t1 + t2;
			}
			
			s.h[0] += a;
			s.h[1] += b;
			s.h[2] += c;
			s.h[3] += d;
			s.h[4] += e;
			s.h[5] += f;
			s.h[6] += g;
			s.h[7] += h;
		}
		
		static void pad(sha256* s)
		{
			ubyte r = s.len % 64;
		
			s.buf[r++] = 0x80;
			
			if (r > 56)
			{
				memset(cast(ubyte*) s.buf.ptr + r, 0, 64 - r);
				r = 0;
				processblock(s, cast(ubyte*) s.buf.ptr);
			}
			
			memset(cast(ubyte*) s.buf.ptr + r, 0, 56 - r);
			
			s.len *= 8;
			s.buf[56] = cast(ubyte) (s.len >> 56);
			s.buf[57] = cast(ubyte) (s.len >> 48);
			s.buf[58] = cast(ubyte) (s.len >> 40);
			s.buf[59] = cast(ubyte) (s.len >> 32);
			s.buf[60] = cast(ubyte) (s.len >> 24);
			s.buf[61] = cast(ubyte) (s.len >> 16);
			s.buf[62] = cast(ubyte) (s.len >> 8);
			s.buf[63] = cast(ubyte) s.len;
			
			processblock(s, cast(ubyte*) s.buf.ptr);
		}
		
		static void sha256_init(sha256* s)
		{
			s.len = 0;
			s.h[0] = 0x6a09e667;
			s.h[1] = 0xbb67ae85;
			s.h[2] = 0x3c6ef372;
			s.h[3] = 0xa54ff53a;
			s.h[4] = 0x510e527f;
			s.h[5] = 0x9b05688c;
			s.h[6] = 0x1f83d9ab;
			s.h[7] = 0x5be0cd19;
		}
		
		static void sha256_sum(sha256* s, ubyte* md)
		{
			int i;
		
			pad(s);
			
			for (i = 0; i < 8; i++)
			{
				md[4*i]   = cast(ubyte) (s.h[i] >> 24);
				md[4*i+1] = cast(ubyte) (s.h[i] >> 16);
				md[4*i+2] = cast(ubyte) (s.h[i] >> 8);
				md[4*i+3] = cast(ubyte) (s.h[i]);
			}
		}
		
		static void sha256_update(sha256* s, const(void*) m, ulong len)
		{
			ubyte* p = cast(ubyte*) m;
			uint r = s.len % 64;
		
			s.len += len;
			
			if (r)
			{
				if (len < 64 - r)
				{
					memcpy(cast(ubyte*) s.buf.ptr + r, p, len);
					return;
				}
				
				memcpy(cast(ubyte*) s.buf.ptr + r, p, 64 - r);
				len -= 64 - r;
				p += 64 - r;
				
				processblock(s, cast(ubyte*) s.buf.ptr);
			}
			
			for (; len >= 64; len -= 64, p += 64)
			{
				processblock(s, cast(ubyte*) p);
			}
			
			memcpy(cast(ubyte*) s.buf.ptr, p, len);
		}

		__gshared int dir_fd = -1;
		__gshared int dep_fd = -1;
		__gshared int poolwr_fd = -1;
		__gshared int poolrd_fd = -1;
		__gshared int level = -1;
		__gshared int implicit_jobs = 1;
		__gshared int kflag, jflag, xflag, fflag, sflag;
		
		static void redo_ifcreate(int fd, char* target)
		{
			dprintf(fd, "-%s\n", target);
		}
		
		static char* check_dofile(const char *fmt, ...)
		{
			static char[PATH_MAX] dofile;
		
			va_list ap;
			va_start(ap, fmt);
			vsnprintf(cast(char*) dofile.ptr, dofile.sizeof, fmt, ap);
			va_end(ap);
		
			if (access(cast(char*) dofile.ptr, F_OK) == 0)
			{
				return cast(char*) dofile.ptr;
			}
			else
			{
				redo_ifcreate(dep_fd, cast(char*) dofile.ptr);
				return cast(char*) 0;
			}
		}
		
		static char* find_dofile(char* target)
		{
			char[PATH_MAX] updir;
			char* u = cast(char*) updir.ptr;
			char* dofile, s;
			stat_t st, ost;
		
			dofile = check_dofile("./%s.do", target);
			
			if (dofile)
			{
				return dofile;
			}
		
			*u++ = '.';
			*u++ = '/';
			*u = 0;
		
			st.st_dev  = 0;
			ost.st_dev = 0;
			st.st_ino  = 0;
			ost.st_ino = 0;
		
			while (1)
			{
				ost = st;
		
				if (stat(cast(char*) updir.ptr, &st) < 0)
				{
					return cast(char*) 0;
				}
				
				if ((ost.st_dev == st.st_dev) && (ost.st_ino == st.st_ino))
				{
					break;
				}
		
				s = target;
				while (*s)
				{
					if (*s++ == '.')
					{
						dofile = check_dofile("%sdefault.%s.do", cast(char*) 
updir.ptr, s);
						if (dofile)
						{
							return dofile;
						}
					}
				}
		
				dofile = check_dofile("%sdefault.do", cast(char*) updir.ptr);
				
				if (dofile)
				{
					return dofile;
				}
		
				*u++ = '.';
				*u++ = '.';
				*u++ = '/';
				*u = 0;
			}
		
			return cast(char*) 0;
		}
		
		static int envfd(const char* name)
		{
			long fd;
			char* s = getenv(name);
			
			if (!s)
			{
				return -1;
			}
		
			fd = strtol(s, null, 10);
			
			if ((fd < 0) || (fd > 255))
			{
				fd = -1;
			}
		
			return cast(int) fd;
		}
		
		static void setenvfd(const char* name, int i)
		{
			char[16] buf;
			snprintf(cast(char*) buf.ptr, buf.sizeof, "%d", i);
			setenv(name, cast(char*) buf.ptr, 1);
		}
		
		static char* hashfile(int fd)
		{
			static char[16] hex = "0123456789abcdef";
			static char[65] asciihash;
		
			sha256 ctx;
			off_t off = 0;
			char[4096] buf;
			char* a;
			char[32] hash;
			int i;
			ssize_t r;
		
			sha256_init(&ctx);
		
			while ((r = pread(fd, cast(char*) buf.ptr, buf.sizeof, off)) > 
0)
			{
				sha256_update(&ctx, cast(char*) buf, r);
				off += r;
			}
		
			sha256_sum(&ctx, cast(ubyte*) hash);
		
			for (i = 0, a = cast(char*) asciihash.ptr; i < 32; i++)
			{
				*a++ = hex[hash[i] / 16];
				*a++ = hex[hash[i] % 16];
			}
			
			*a = 0;
		
			return cast(char*) asciihash.ptr;
		}
				
		static char* datefile(int fd)
		{
			static char[17] hexdate;
			stat_t st;
		
			fstat(fd, &st);
			
			snprintf(cast(char*) hexdate.ptr, hexdate.sizeof, cast(char*) 
("%016" ~ cast(string) PRIx64), cast(ulong) st.st_ctime);
		
			return cast(char*) hexdate.ptr;
		}
		
		static int keepdir()
		{
			int fd = open(".", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
			
			if (fd < 0)
			{
				perror("dir open");
				exit(-1);
			}
			
			return fd;
		}
		
		static char* targetchdir(char* target)
		{
			char* base = strrchr(target, '/');
			
			if (base)
			{
				int fd;
				*base = 0;
				
				fd = openat(dir_fd, target, O_RDONLY | O_DIRECTORY);
				
				if (fd < 0)
				{
					perror("openat dir");
					exit(111);
				}
				
				*base = '/';
				
				if (fchdir(fd) < 0)
				{
					perror("chdir");
					exit(111);
				}
				
				close(fd);
				
				return base + 1;
			}
			else
			{
				fchdir(dir_fd);
				return target;
			}
		}
		
		static char* targetdep(char* target)
		{
			static char[PATH_MAX] buf;
			
			snprintf(cast(char*) buf.ptr, buf.sizeof, ".dep.%s", target);
			
			return cast(char*) buf.ptr;
		}
		
		static char* targetlock(char* target)
		{
			static char[PATH_MAX] buf;
			
			snprintf(cast(char*) buf.ptr, buf.sizeof, ".lock.%s", target);
			
			return cast(char*) buf.ptr;
		}
		
		static int sourcefile(char* target)
		{
			if (access(targetdep(target), F_OK) == 0)
			{
				return 0;
			}
		
			if (fflag < 0)
			{
				return access(target, F_OK) == 0;
			}
		
			return (find_dofile(target) == cast(char*) 0);
		}
		
		static int check_deps(char* target)
		{
			char* depfile;
			FILE* f;
			int ok = 1;
			int fd;
			int old_dir_fd = dir_fd;
		
			target = targetchdir(target);
		
			if (sourcefile(target))
			{
				return 1;
			}
		
			if (fflag > 0)
			{
				return 0;
			}
		
			depfile = targetdep(target);
			f = fopen(depfile, "r");
			if (!f)
			{
				return 0;
			}
		
			dir_fd = keepdir();
		
			while (ok && !feof(f))
			{
				char[4096] line;
				char* hash = cast(char*) line.ptr + 1;
				char* timestamp = cast(char*) line.ptr + 1 + 64 + 1;
				char* filename = cast(char*) line.ptr + 1 + 64 + 1 + 16 + 1;
		
				if (fgets(cast(char*) line.ptr, line.sizeof, f))
				{
					line[strlen(cast(char*) line.ptr)-1] = 0;
					switch (line[0])
					{
						case '-':
							if (access(cast(char*) line.ptr + 1, F_OK) == 0)
							{
								ok = 0;
							}
							break;
						case '=':
							fd = open(filename, O_RDONLY);
							if (fd < 0)
							{
								ok = 0;
							}
							else
							{
								if (strncmp(timestamp, datefile(fd), 16) != 0 && 
strncmp(hash, hashfile(fd), 64) != 0)
								{
									ok = 0;
								}
								close(fd);
							}
							
							if (ok && strcmp(target, filename) != 0)
							{
								ok = check_deps(filename);
								fchdir(dir_fd);
							}
							break;
						case '!':
						default:
							ok = 0;
					}
				}
				else
				{
					if (!feof(f))
					{
						ok = 0;
						break;
					}
				}
			}
		
			fclose(f);
		
			close(dir_fd);
			dir_fd = old_dir_fd;
		
			return ok;
		}
		
		void vacate(int implicit)
		{
			if (implicit)
			{
				implicit_jobs++;
			}
			else
			{
				write(poolwr_fd, cast(char*) "\0".ptr, 1);
			}
		}
		
		struct job
		{
			job* next;
			pid_t pid;
			int lock_fd;
			char* target, temp_depfile, temp_target;
			int implicit;
		}

		__gshared job* jobhead;
		
		static void insert_job(job* jobn)
		{
			jobn.next = jobhead;
			jobhead = jobn;
		}
		
		static void remove_job(job* jobn)
		{
			if (jobhead == jobn)
			{
				jobhead = jobhead.next;
			}
			else
			{
				job* j = jobhead;
				while (j.next != jobn)
				{
					j = j.next;
				}
				
				j.next = j.next.next;
			}
		}
		
		static job* find_job(pid_t pid)
		{
			job* j;
		
			for (j = jobhead; j; j = j.next)
			{
				if (j.pid == pid)
				{
					return j;
				}
			}
		
			return cast(job*) 0;
		}
		
		__gshared char[PATH_MAX] uprel = "\0";
		
		void compute_uprel()
		{
			char* u = cast(char*) uprel.ptr;
			char* dp = getenv("REDO_DIRPREFIX");
		
			*u = 0;
			while (dp && *dp) {
				*u++ = '.';
				*u++ = '.';
				*u++ = '/';
				*u = 0;
				dp = strchr(dp + 1, '/');
			}
		}
		
		static int write_dep(int dep_fd, const(char*) file)
		{
			int fd = open(file, O_RDONLY);
			
			if (fd < 0)
			{
				return 0;
			}
				
			dprintf(dep_fd, "=%s %s %s%s\n", hashfile(fd), datefile(fd), 
(*file == '/' ? "" : cast(char*) uprel.ptr), file);
			close(fd);
			
			return 0;
		}
		
		int new_waitjob(int lock_fd, int implicit)
		{
			pid_t pid;
		
			pid = fork();
			if (pid < 0) {
				perror("fork");
				vacate(implicit);
				exit(-1);
			} else if (pid == 0) {
				lockf(lock_fd, F_LOCK, 0);
				close(lock_fd);
				exit(0);
			} else {
				job* job;
				
				if (!job)
				{	
					exit(-1);
				}
				
				job.target = cast(char*) 0;
				job.pid = pid;
				job.lock_fd = lock_fd;
				job.implicit = implicit;
		
				insert_job(job);
			}
		
			return cast(char*) 0;
		}
		
		static char* redo_basename(char* dofile, char* target)
		{
			static char[PATH_MAX] buf = "\0";
			int stripext = 0;
			char* s;
		
			if (strncmp(dofile, "default.", 8) == 0)
			{
				for (stripext = -1, s = dofile; *s; s++)
				{
					if (*s == '.')
					{
						stripext++;
					}
				}
			}
		
			strncpy(cast(char*) buf.ptr, target, buf.sizeof);
			while (stripext--> 0)
			{
				if (strchr(cast(char*) buf.ptr, '.'))
				{
					char* e = strchr(cast(char*) buf.ptr, '\0');
					while (*--e != '.')
					{
						*e = 0;
					}
					*e = 0;
				}
			}
		
			return cast(char*) buf.ptr;
		}
		
		static void run_script(char* target, int implicit)
		{
			
			char[15] temp_depfile = cast(char[]) ".depend.XXXXXX\0";
			char[15] temp_target_base = cast(char[]) ".target.XXXXXX\0";
			char[PATH_MAX] temp_target = "\0",
						   rel_target = "\0",
						   cwd = "\0";
			char* orig_target = target;
			int old_dep_fd = dep_fd;
			int target_fd;
			char* dofile, dirprefix;
			pid_t pid;
		
			target = targetchdir(target);
			dofile = find_dofile(target);
			
			if (!dofile)
			{
				fprintf(stderr, "no dofile for %s.\n", target);
				exit(1);
			}
			
			int lock_fd = open(targetlock(target), O_WRONLY | O_TRUNC | 
O_CREAT, 0x1b6);
			
			if (lockf(lock_fd, F_TLOCK, 0) < 0)
			{
				if (errno == EAGAIN)
				{
					fprintf(stderr, "redo: %s already building, waiting.\n", 
orig_target);
					new_waitjob(lock_fd, implicit);
					return;
				}
				else
				{
					perror("lockf");
					exit(111);
				}
			}
			
			dep_fd = mkstemp(cast(char*) temp_depfile.ptr);
			target_fd = mkstemp(cast(char*) temp_target_base.ptr);
			
			fprintf(stderr, "redo%*.*s %s # %s\n", level*2, level*2, 
cast(char*) " ".ptr, orig_target, dofile);
			write_dep(dep_fd, dofile);
		
			getcwd(cast(char*) cwd.ptr, cwd.sizeof);
			dirprefix = strchr(cast(char*) cwd.ptr, '\0');
			dofile += 2;
			
			while (strncmp(dofile, "../", 3) == 0)
			{
				chdir("..");
				dofile += 3;
				while (*--dirprefix != '/')
					{}
			}
			
			if (*dirprefix)
			{
				dirprefix++;
			}
		
			
			snprintf(cast(char*) temp_target.ptr, temp_target.sizeof, 
"%s%s%s", dirprefix, (*dirprefix ? cast(char*) "/".ptr : 
cast(char*) "".ptr), cast(char*) temp_target_base.ptr);
			snprintf(cast(char*) rel_target.ptr, rel_target.sizeof, 
"%s%s%s", dirprefix, (*dirprefix ? cast(char*) "/".ptr : 
cast(char*) "".ptr), target);
		
			setenv("REDO_DIRPREFIX", dirprefix, 1);
		
			pid = fork();
			if (pid < 0)
			{
				perror("fork");
				vacate(implicit);
				exit(-1);
			} else if (pid == 0) {
		
				char* basename = redo_basename(dofile, cast(char*) 
rel_target.ptr);
		
				if (old_dep_fd > 0)
				{
					close(old_dep_fd);
				}
				close(lock_fd);
				setenvfd("REDO_DEP_FD", dep_fd);
				setenvfd("REDO_LEVEL", level + 1);
				
				if (sflag > 0)
				{
					dup2(target_fd, 1);
				}
				else
				{
					close(target_fd);
				}
		
				if (access(dofile, X_OK) != 0)
				{
					execl(
						cast(char*) "/bin/sh".ptr,
						cast(char*) "/bin/sh".ptr,
						(xflag > 0) ? (cast(char*) "-ex".ptr) : (cast(char*) 
"-e".ptr),
						dofile,
						cast(char*) rel_target.ptr,
						basename,
						cast(char*) temp_target.ptr,
						cast(char*) 0
					);
				}
				else
				{
					execl(
						dofile,
						dofile,
						cast(char*) rel_target.ptr,
						basename,
						cast(char*) temp_target.ptr,
						cast(char*) 0
					);
				}
				
				vacate(implicit);
				exit(-1);
			} else {
				job* job;
				if (!job)
				{
					exit(-1);
				}
		
				close(target_fd);
				close(dep_fd);
				dep_fd = old_dep_fd;
		
				job.pid = pid;
				job.lock_fd = lock_fd;
				job.target = orig_target;
				job.temp_depfile = strdup(cast(char*) temp_depfile.ptr);
				job.temp_target = strdup(cast(char*) temp_target_base.ptr);
				job.implicit = implicit;
		
				insert_job(job);
			}
		}

		static int try_procure()
		{
			if (implicit_jobs > 0)
			{
				implicit_jobs--;
				return 1;
			}
			else
			{
				if (poolrd_fd < 0)
				{
					return 0;
				}
		
				fcntl(poolrd_fd, F_SETFL, O_NONBLOCK);
		
				char[1] buf;
				
				return read(poolrd_fd, &buf, 1) > 0;
			}
		}
		
		static int procure()
		{
			if (implicit_jobs > 0)
			{
				implicit_jobs--;
				return 1;
			}
			else
			{
				fcntl(poolrd_fd, F_SETFL, 0);
		
				char[1] buf;
				return read(poolrd_fd, &buf, 1) > 0;
			}
		}

		void create_pool()
		{
			poolrd_fd = envfd(cast(char*) "REDO_RD_FD".ptr);
			poolwr_fd = envfd(cast(char*) "REDO_WR_FD".ptr);
			
			if (poolrd_fd < 0 || poolwr_fd < 0)
			{
				int jobs = envfd(cast(char*) "JOBS".ptr);
				if (jobs > 1)
				{
					int i;
					int[2] fds;
					pipe(fds);
					poolrd_fd = fds[0];
					poolwr_fd = fds[1];
		
					for (i = 0; i < jobs-1; i++)
					{
						vacate(0);
					}
		
					setenvfd(cast(char*) "REDO_RD_FD".ptr, poolrd_fd);
					setenvfd(cast(char*) "REDO_WR_FD".ptr, poolwr_fd);
				}
				else
				{
					poolrd_fd = -1;
					poolwr_fd = -1;
				}
			}
		}

		static void redo_ifchange(int targetc, char** targetv)
		{
			pid_t pid;
			int status;
			job* job;
		
			int targeti = 0;
			
			char[4096] buf = void;
			char* skip = cast(char*) buf.ptr;
			
			create_pool();
			
			for (targeti = 0; targeti < targetc; targeti++)
			{
				skip[targeti] = cast(char) check_deps(targetv[targeti]);
				printf("steps %d - %s\n", targetv[targeti]);
			}
			
			printf("targetc = %d\n", targetc);
				
			targeti = 0;
			while (1)
			{
				int procured = 0;
				
				if (targeti < targetc)
				{
					char* target = cast(char*) targetv[targeti];
		
					if (skip[targeti])
					{
						targeti++;
						continue;
					}
		
					int implicit = implicit_jobs > 0;
					
					if (try_procure())
					{
						procured = 1;
						targeti++;
						run_script(target, implicit);
					}
				}
				
				printf("error here\n");
		
				pid = waitpid(-1, &status, procured ? WNOHANG : 0);
				
				printf("pid = %d", pid);
		
				if (pid == 0)
				{
					continue;
				}
		
				if (pid < 0)
				{
					if (errno == ECHILD && targeti < targetc)
					{
						continue;
					}
					else
					{
						break;
					}
				}
		
				if (WIFEXITED(status))
				{
					status = WEXITSTATUS(status);
				}
				
				printf("error in find job\n");
		
				job = find_job(pid);
		
				if (!job)
				{
					exit(-1);
				}
				
				printf("error in remove job\n");
				remove_job(job);
		
				if (job.target)
				{
					if (status > 0)
					{
						remove(job.temp_depfile);
						remove(job.temp_target);
					}
					else
					{
						stat_t st;
						char* target = targetchdir(job.target);
						char* depfile = targetdep(target);
						int dfd;
		
						dfd = open(job.temp_depfile, O_WRONLY | O_APPEND);
						if (stat(job.temp_target, &st) == 0)
						{
							rename(job.temp_target, target);
							write_dep(dfd, target);
						}
  						else
						{
							remove(job.temp_target);
							redo_ifcreate(dfd, target);
						}
						close(dfd);
		
						rename(job.temp_depfile, depfile);
						remove(targetlock(target));
					}
				}
		
				close(job.lock_fd);
		
				vacate(job.implicit);
		
				if ((kflag < 0) && (status > 0))
				{
					printf("failed with status %d\n", status);
					exit(status);
				}
			}
		}
		
		static void record_deps(int targetc, char** targetv)
		{
			int targeti = 0;
			int fd;
		
			dep_fd = envfd("REDO_DEP_FD");
			if (dep_fd < 0)
			{
				return;
			}
		
			fchdir(dir_fd);
		
			for (targeti = 0; targeti < targetc; targeti++)
			{
				fd = open(targetv[targeti], O_RDONLY);
				if (fd < 0)
				{
					continue;
				}
				write_dep(dep_fd, targetv[targeti]);
				close(fd);
			}
		}
		
		int main(int argc, char** argv)
		{
			char* program;
			int opt = 0, i = 0;
			
			dep_fd = envfd(cast(char*) "REDO_DEP_FD".ptr);
			level = envfd(cast(char*) "REDO_LEVEL".ptr);
			
			if (level < 0)
			{
				level = 0;
			}
			
			char* progname = strrchr(cast(char*) argv[0], cast(char*) '/');
			
			if (progname !is null)
			{
				program = progname;
				program++;
			}
			else
			{
				program = argv[0];
			}
						
			while ((opt = getopt(argc, argv, "+kxfsj:C:")) != -1)
			{
				switch (opt)
				{
				case 'k':
					setenvfd(cast(char*) "REDO_KEEP_GOING".ptr, 1);
					break;
				case 'x':
					setenvfd(cast(char*) "REDO_TRACE".ptr, 1);
					break;
				case 'f':
					setenvfd(cast(char*) "REDO_FORCE".ptr, 1);
					break;
				case 's':
					setenvfd(cast(char*) "REDO_STDOUT".ptr, 1);
					break;
				case 'j':
					setenv(cast(char*) "JOBS".ptr, optarg, 1);
					break;
				case 'C':
					if (chdir(optarg) < 0)
					{
						perror("chdir");
						exit(-1);
					}
					break;
				default:
					fprintf(stderr, "usage: %s [-kfsx] [-jN] [-Cdir] 
[TARGETS...]\n", program);
					exit(1);
					break;
				}
			}			
			argc -= optind;
			argv += optind;
			
			fflag = envfd(cast(char*) "REDO_FORCE".ptr);
			kflag = envfd(cast(char*) "REDO_KEEP_GOING".ptr);
			xflag = envfd(cast(char*) "REDO_TRACE".ptr);
			sflag = envfd(cast(char*) "REDO_STDOUT".ptr);
		
			dir_fd = keepdir();
			
			if (strcmp(program, cast(char*) "redo".ptr) == 0)
			{	
				char* all = cast(char*) "all".ptr;
				char*[1] argv_def = [all];
				
				if (argc == 0)
				{
				    argc = 1;
				    argv = argv_def.ptr;
				    printf("%s", argv[0]);
				}

				
				fflag = 1;
				
				printf("%s", argv);
				redo_ifchange(argc, argv);
				procure();
			} else if (strcmp(program, cast(char*) "redo-ifchange".ptr) == 
0) {
				compute_uprel();
				redo_ifchange(argc, argv);
				record_deps(argc, argv);
				procure();
			} else if (strcmp(program, cast(char*) "redo-ifcreate".ptr) == 
0) {
				for (i = 0; i < argc; i++)
				{
					redo_ifcreate(dep_fd, argv[i]);
				}
			} else if (strcmp(program, cast(char*) "redo-always".ptr) == 
0) {
				dprintf(dep_fd, "!\n");
			} else if (strcmp(program, cast(char*) "redo-hash".ptr) == 0) {
				for (i = 0; i < argc; i++)
				{
					write_dep(1, cast(const(char*)) argv[i]);
				}
			} else {
				fprintf(stderr, "not implemented %s\n", program);
				exit(-1);
			}
			
			return 0;
		}
     }
}
```


More information about the Digitalmars-d mailing list