Thread overview
Some questions about porting code from C to BetterC
Nov 30, 2021
Bagomot
Nov 30, 2021
Dennis
Nov 30, 2021
Bagomot
Nov 30, 2021
Dennis
Nov 30, 2021
Bagomot
Nov 30, 2021
Dennis
November 30, 2021

Hello! Please tell me how to translate this snippet from C in BetterC:

char all[] = "all";
char *argv_def[] = { all };
if (argc == 0) {
    argc = 1;
    argv = argv_def;
}
November 30, 2021

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:

char all[] = "all";
char *argv_def[] = { all };
if (argc == 0) {
    argc = 1;
    argv = argv_def;
}
const(char)* all = "all";
const(char)*[1] argv_def = [all];
if (argc == 0) {
    argc = 1;
    argv = &argv_def;
}
November 30, 2021

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:

char all[] = "all";
char *argv_def[] = { all };
if (argc == 0) {
    argc = 1;
    argv = argv_def;
}
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:

Error: cannot implicitly convert expression & argv_def of type const(char)*[1]* to char**
November 30, 2021

On Tuesday, 30 November 2021 at 19:49:32 UTC, Bagomot wrote:

>

I get an error with this code:

Error: cannot implicitly convert expression & argv_def of type const(char)*[1]* to char**

Sorry, should be:

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)**.

November 30, 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.

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;
		}
    }
}
November 30, 2021

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.