www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Some questions about porting code from C to BetterC

reply Bagomot <bagomot gmail.com> writes:
Hello! Please tell me how to translate this snippet from C in 
BetterC:
```c
char all[] = "all";
char *argv_def[] = { all };
if (argc == 0) {
     argc = 1;
     argv = argv_def;
}
```
Nov 30 2021
parent reply Dennis <dkorpel gmail.com> writes:
On Tuesday, 30 November 2021 at 19:07:14 UTC, Bagomot wrote:
 Hello! Please tell me how to translate this snippet from C in 
 BetterC:
 ```c
 char all[] = "all";
 char *argv_def[] = { all };
 if (argc == 0) {
     argc = 1;
     argv = argv_def;
 }
 ```
```D const(char)* all = "all"; const(char)*[1] argv_def = [all]; if (argc == 0) { argc = 1; argv = &argv_def; } ```
Nov 30 2021
parent reply Bagomot <bagomot gmail.com> writes:
On Tuesday, 30 November 2021 at 19:09:22 UTC, Dennis wrote:
 On Tuesday, 30 November 2021 at 19:07:14 UTC, Bagomot wrote:
 Hello! Please tell me how to translate this snippet from C in 
 BetterC:
 ```c
 char all[] = "all";
 char *argv_def[] = { all };
 if (argc == 0) {
     argc = 1;
     argv = argv_def;
 }
 ```
```D const(char)* all = "all"; const(char)*[1] argv_def = [all]; if (argc == 0) { argc = 1; argv = &argv_def; } ```
I get an error with this code: ```text Error: cannot implicitly convert expression & argv_def of type const(char)*[1]* to char** ```
Nov 30 2021
parent reply Dennis <dkorpel gmail.com> writes:
On Tuesday, 30 November 2021 at 19:49:32 UTC, Bagomot wrote:
 I get an error with this code:
 ```text
 Error: cannot implicitly convert expression & argv_def of type 
 const(char)*[1]* to char**
 ```
Sorry, should be: ```D const(char)* all = "all"; const(char)*[1] argv_def = [all]; if (argc == 0) { argc = 1; argv = argv_def.ptr; // <-- .ptr instead of &argv_def } ``` .ptr gives a pointer to the first element of the static array, which is what arrays implicitly convert to in C. From your error message I gather the type of `argv` is `char**`. Since you assign it a string literal, you should make it `const(char)**`.
Nov 30 2021
parent reply Bagomot <bagomot gmail.com> writes:
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);
			

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;
		}
     }
}
```
Nov 30 2021
parent Dennis <dkorpel gmail.com> writes:
On Tuesday, 30 November 2021 at 21:05:46 UTC, Bagomot wrote:
 The for some errors are not clear to me. Write if you have 
 comments or ideas.
First impressions: - You can use `extern(C): version(Posix):` to reduce the indentation level - You're casting away `const` a lot, even when it's not necessary - I skimmed through it in case anything stood out, but "here's 1200 lines of code, there's some error in it" is a bit of a tough assignment :p Here's the safest way to translate C code: - Translate the header to D and call the original C code from D, verify that it works - Incrementally remove functions from the C code and provide a translated D implementation for them instead. Verify that the code still works after each step, so you can find translation errors early. - Once all C functions are translated, you can throw away the D header and stop linking with the C code, you're done! Translating it all in one bunch might be faster if you pull it off, but then you run the risk of getting into the situation you are in right now, and then you have to debug.
Nov 30 2021