From fb745e80e321018ca0b5b5dc80d25b9f6145481e Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Mon, 21 May 2018 22:42:19 -0400 Subject: [PATCH 01/30] Started the tool to convert Windows API functions into HRESULT wrappers. --- windows/tools/hresultwrap.cpp | 158 ++++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 windows/tools/hresultwrap.cpp diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp new file mode 100644 index 00000000..05388837 --- /dev/null +++ b/windows/tools/hresultwrap.cpp @@ -0,0 +1,158 @@ +// 21 may 2018 +#include +#include +#include + +#define nbuf 1024 + +bool generate(std::vector *genline, FILE *fout) +{ + std::vector genout(nbuf); + size_t nw; + + genout.push_back('/'); + genout.push_back('/'); + genout.push_back(' '); + genout.insert(genout.end(), genline->begin(), genline->end()); + genout.push_back('\n'); + + genout.push_back('\n'); + nw = fwrite(genout.data(), sizeof (char), genout.size(), fout); + return nw != genout.size(); +} + +struct process { + // each of these returns the number of bytes in buf that were processed + size_t (*state)(struct process *p, const char *buf, size_t n, FILE *fout); + bool error; + std::vector *genline; +}; + +static size_t stateError(struct process *p, const char *buf, size_t n, FILE *fout) +{ + p->error = true; + return n; +} + +size_t stateCopyLine(struct process *p, const char *buf, size_t n, FILE *fout); +size_t stateGenerate(struct process *p, const char *buf, size_t n, FILE *fout); + +size_t stateNewLine(struct process *p, const char *buf, size_t n, FILE *fout) +{ + if (n > 0 && buf[0] == '@') { + p->state = stateGenerate; + return 1; // skip the @ + } + p->state = stateCopyLine; + return 0; // don't skip anything +} + +size_t stateCopyLine(struct process *p, const char *buf, size_t n, FILE *fout) +{ + size_t nw; + size_t j; + + for (j = 0; j < n; j++) + if (buf[j] == '\n') { + // include the newline; that's being copied too + j++; + break; + } + nw = fwrite(buf, sizeof (char), j, fout); + if (nw != j) { + p->state = stateError; + return 0; + } + // and on to the next line + p->state = stateNewLine; + return j; +} + +size_t stateGenerate(struct process *p, const char *buf, size_t n, FILE *fout) +{ + size_t j; + + if (p->genline == NULL) + p->genline = new std::vector(n); + for (j = 0; j < n; j++) + if (buf[j] == '\n') + // do NOT include the newline this time + break; + p->genline->insert(p->genline->end(), buf, buf + j); + if (j == n) // '\n' not found; not finished with the line yet + return j; + // finished with the line; process it and continue + p->state = stateNewLine; + if (!generate(p->genline, fout)) + p->state = stateError; + delete p->genline; + p->genline = NULL; + // buf[j] == '\n' and generate() took care of printing a newline + return j + 1; +} + +void processInit(struct process *p) +{ + memset(p, 0, sizeof (struct process)); + p->state = stateNewLine; +} + +bool process(struct process *p, const char *buf, size_t n, FILE *fout) +{ + size_t np; + + while (n != 0) { + np = (*(p->state))(p, buf, n, fout); + buf += np; + n -= np; + } + return p->error; +} + +int main(int argc, char *argv[]) +{ + FILE *fin = NULL, *fout = NULL; + char buf[nbuf]; + size_t n; + struct process p; + int ret = 1; + + if (argc != 3) { + fprintf(stderr, "usage: %s infile outfile\n", argv[0]); + return 1; + } + + fin = fopen(argv[1], "rb"); + if (fin == NULL) { + fprintf(stderr, "error opening %s\n", argv[1]); + goto done; + } + fout = fopen(argv[2], "wb"); + if (fout == NULL) { + fprintf(stderr, "error creating %s\n", argv[2]); + goto done; + } + + processInit(&p); + for (;;) { + n = fread(buf, sizeof (char), nbuf, fin); + if (n == 0) + break; + if (!process(&p, buf, n, fout)) { + fprintf(stderr, "error writing to %s\n", argv[2]); + goto done; + } + } + if (!feof(fin)) { + fprintf(stderr, "error reading from %s\n", argv[1]); + goto done; + } + + ret = 0; +done: + if (fin != NULL) + fclose(fin); + if (fout != NULL) + fclose(fout); + return ret; +} From d09be0d5fc3231ccbe2159f704ba8e7ff38d9949 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Mon, 21 May 2018 23:05:39 -0400 Subject: [PATCH 02/30] Fixed bugs in hresultwrap.cpp. --- windows/tools/hresultwrap.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 05388837..aef118da 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -3,11 +3,9 @@ #include #include -#define nbuf 1024 - bool generate(std::vector *genline, FILE *fout) { - std::vector genout(nbuf); + std::vector genout; size_t nw; genout.push_back('/'); @@ -18,7 +16,7 @@ bool generate(std::vector *genline, FILE *fout) genout.push_back('\n'); nw = fwrite(genout.data(), sizeof (char), genout.size(), fout); - return nw != genout.size(); + return nw == genout.size(); } struct process { @@ -73,7 +71,7 @@ size_t stateGenerate(struct process *p, const char *buf, size_t n, FILE *fout) size_t j; if (p->genline == NULL) - p->genline = new std::vector(n); + p->genline = new std::vector; for (j = 0; j < n; j++) if (buf[j] == '\n') // do NOT include the newline this time @@ -82,9 +80,11 @@ size_t stateGenerate(struct process *p, const char *buf, size_t n, FILE *fout) if (j == n) // '\n' not found; not finished with the line yet return j; // finished with the line; process it and continue - p->state = stateNewLine; - if (!generate(p->genline, fout)) + if (!generate(p->genline, fout)) { p->state = stateError; + return 0; + } + p->state = stateNewLine; delete p->genline; p->genline = NULL; // buf[j] == '\n' and generate() took care of printing a newline @@ -106,9 +106,11 @@ bool process(struct process *p, const char *buf, size_t n, FILE *fout) buf += np; n -= np; } - return p->error; + return !p->error; } +#define nbuf 1024 + int main(int argc, char *argv[]) { FILE *fin = NULL, *fout = NULL; From b769b37189997dab418d79f110ae52fc2615ed7b Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 22 May 2018 21:03:54 -0400 Subject: [PATCH 03/30] Attempted to simplify hresultwrap.cpp through a Scanner class, similar to Go's bufio.Scanner. There are a few snags right now... --- windows/tools/hresultwrap.cpp | 175 +++++++++++++++++----------------- 1 file changed, 88 insertions(+), 87 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index aef118da..350bf517 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -19,98 +19,99 @@ bool generate(std::vector *genline, FILE *fout) return nw == genout.size(); } -struct process { - // each of these returns the number of bytes in buf that were processed - size_t (*state)(struct process *p, const char *buf, size_t n, FILE *fout); +class Scanner { + FILE *fin; + char *buf; + const char *p; + size_t n; + std::vector *line; + bool eof; bool error; - std::vector *genline; +public: + Scanner(FILE *fin); + ~Scanner(void); + + bool Scan(void); + std::vector::const_iterator BytesBegin(void) const; + std::vector::const_iterator BytesEnd(void) const; + bool Error(void) const; }; -static size_t stateError(struct process *p, const char *buf, size_t n, FILE *fout) -{ - p->error = true; - return n; -} - -size_t stateCopyLine(struct process *p, const char *buf, size_t n, FILE *fout); -size_t stateGenerate(struct process *p, const char *buf, size_t n, FILE *fout); - -size_t stateNewLine(struct process *p, const char *buf, size_t n, FILE *fout) -{ - if (n > 0 && buf[0] == '@') { - p->state = stateGenerate; - return 1; // skip the @ - } - p->state = stateCopyLine; - return 0; // don't skip anything -} - -size_t stateCopyLine(struct process *p, const char *buf, size_t n, FILE *fout) -{ - size_t nw; - size_t j; - - for (j = 0; j < n; j++) - if (buf[j] == '\n') { - // include the newline; that's being copied too - j++; - break; - } - nw = fwrite(buf, sizeof (char), j, fout); - if (nw != j) { - p->state = stateError; - return 0; - } - // and on to the next line - p->state = stateNewLine; - return j; -} - -size_t stateGenerate(struct process *p, const char *buf, size_t n, FILE *fout) -{ - size_t j; - - if (p->genline == NULL) - p->genline = new std::vector; - for (j = 0; j < n; j++) - if (buf[j] == '\n') - // do NOT include the newline this time - break; - p->genline->insert(p->genline->end(), buf, buf + j); - if (j == n) // '\n' not found; not finished with the line yet - return j; - // finished with the line; process it and continue - if (!generate(p->genline, fout)) { - p->state = stateError; - return 0; - } - p->state = stateNewLine; - delete p->genline; - p->genline = NULL; - // buf[j] == '\n' and generate() took care of printing a newline - return j + 1; -} - -void processInit(struct process *p) -{ - memset(p, 0, sizeof (struct process)); - p->state = stateNewLine; -} - -bool process(struct process *p, const char *buf, size_t n, FILE *fout) -{ - size_t np; - - while (n != 0) { - np = (*(p->state))(p, buf, n, fout); - buf += np; - n -= np; - } - return !p->error; -} - #define nbuf 1024 +Scanner::Scanner(FILE *fin) +{ + this->fin = fin; + this->buf = new char[nbuf]; + this->p = this->buf; + this->n = 0; + this->line = new std::vector; + this->eof = false; + this->error = false; +} + +Scanner::~Scanner(void) +{ + delete this->line; + delete[] this->buf; +} + +bool Scanner::Scan(void) +{ + if (this->eof || this->error) + return false; + this->line->clear(); + for (;;) { + if (this->n > 0) { + size_t j; + bool haveline; + + haveline = false; + for (j = 0; j < this->n; j++) + if (this->p[j] == '\n') { + haveline = true; + break; + } + this->line->insert(this->line->end(), this->p, this->p + j); + this->p += j; + this->n -= j; + if (haveline) { + // swallow the \n for the next time through + this->p++; + this->n--; + return true; + } + // otherwise, the buffer was exhausted in the middle of a line, so fall through + } + // need to refill the buffer + this->n = fread(this->buf, sizeof (char), nbuf, this->fin); + if (this->n < nbuf) { + // TODO what if this->eof && this->error? the C standard does not expressly disallow this + this->eof = feof(this->fin) != 0; + this->error = ferror(this->fin) != 0; + if (this->eof || this->error) + return false; + // otherwise process this last chunk of the file + } + this->p = this->buf; + } +} + +std::vector::const_iterator Scanner::BytesBegin(void) const +{ + return this->line->cbegin(); +} + +std::vector::const_iterator Scanner::BytesEnd(void) const +{ + return this->line->cend(); +} + +bool Scanner::Error(void) const +{ + return this->error; +} + int main(int argc, char *argv[]) { FILE *fin = NULL, *fout = NULL; From c38564a8f744ea4ac8d0b544d75a5f60d65c1563 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 22 May 2018 21:19:54 -0400 Subject: [PATCH 04/30] And integrated Scanner into the mix. C's EOF behavior is gonna make things harder... --- windows/tools/hresultwrap.cpp | 82 ++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 350bf517..3bca19dd 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -3,22 +3,6 @@ #include #include -bool generate(std::vector *genline, FILE *fout) -{ - std::vector genout; - size_t nw; - - genout.push_back('/'); - genout.push_back('/'); - genout.push_back(' '); - genout.insert(genout.end(), genline->begin(), genline->end()); - genout.push_back('\n'); - - genout.push_back('\n'); - nw = fwrite(genout.data(), sizeof (char), genout.size(), fout); - return nw == genout.size(); -} - class Scanner { FILE *fin; char *buf; @@ -32,8 +16,8 @@ public: ~Scanner(void); bool Scan(void); - std::vector::const_iterator BytesBegin(void) const; - std::vector::const_iterator BytesEnd(void) const; + const char *Bytes(void) const; + size_t Len(void) const; bool Error(void) const; }; @@ -97,14 +81,14 @@ bool Scanner::Scan(void) } } -std::vector::const_iterator Scanner::BytesBegin(void) const +const char *Scanner::Bytes(void) const { - return this->line->cbegin(); + return this->line->data(); } -std::vector::const_iterator Scanner::BytesEnd(void) const +size_t Scanner::Len(void) const { - return this->line->cend(); + return this->line->size(); } bool Scanner::Error(void) const @@ -112,12 +96,38 @@ bool Scanner::Error(void) const return this->error; } +bool generate(const char *line, size_t n, FILE *fout) +{ + std::vector genout; + size_t nw; + + genout.push_back('/'); + genout.push_back('/'); + genout.push_back(' '); + genout.insert(genout.end(), line, line + n); + genout.push_back('\n'); + + genout.push_back('\n'); + nw = fwrite(genout.data(), sizeof (char), genout.size(), fout); + return nw == genout.size(); +} + +bool process(const char *line, size_t n, FILE *fout) +{ + size_t nw; + + if (n > 0 && line[0] == '@') + return generate(line + 1, n - 1, fout); + nw = fwrite(line, sizeof (char), n, fout); + if (nw != n) + return false; + return fwrite("\n", sizeof (char), 1, fout) == 1; +} + int main(int argc, char *argv[]) { FILE *fin = NULL, *fout = NULL; - char buf[nbuf]; - size_t n; - struct process p; + Scanner *s = NULL; int ret = 1; if (argc != 3) { @@ -136,26 +146,30 @@ int main(int argc, char *argv[]) goto done; } - processInit(&p); - for (;;) { - n = fread(buf, sizeof (char), nbuf, fin); - if (n == 0) - break; - if (!process(&p, buf, n, fout)) { + s = new Scanner(fin); + while (s->Scan()) { + const char *line; + size_t n; + + line = s->Bytes(); + n = s->Len(); + if (!process(line, n, fout)) { fprintf(stderr, "error writing to %s\n", argv[2]); goto done; } } - if (!feof(fin)) { + if (s->Error()) { fprintf(stderr, "error reading from %s\n", argv[1]); goto done; } ret = 0; done: - if (fin != NULL) - fclose(fin); + if (s != NULL) + delete s; if (fout != NULL) fclose(fout); + if (fin != NULL) + fclose(fin); return ret; } From a5e07be2f5644279b4dbbfaaf7a1263d646a8dcf Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Tue, 22 May 2018 21:23:38 -0400 Subject: [PATCH 05/30] Fixed EOF behavior. --- windows/tools/hresultwrap.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 3bca19dd..cdb78040 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -10,6 +10,7 @@ class Scanner { size_t n; std::vector *line; bool eof; + bool eofNextTime; bool error; public: Scanner(FILE *fin); @@ -68,11 +69,19 @@ bool Scanner::Scan(void) // otherwise, the buffer was exhausted in the middle of a line, so fall through } // need to refill the buffer + if (this->eofNextTime) { + this->eof = true; + return false; + } this->n = fread(this->buf, sizeof (char), nbuf, this->fin); if (this->n < nbuf) { - // TODO what if this->eof && this->error? the C standard does not expressly disallow this - this->eof = feof(this->fin) != 0; + // TODO what if this->eofNextTime && this->error? the C standard does not expressly disallow this + this->eofNextTime = feof(this->fin) != 0; this->error = ferror(this->fin) != 0; + // according to various people in irc.freenode.net/##c, feof() followed by fread() can result in ferror(), so we must be sure not to read twice on a feof() + // however, because a partial (nonzero) fread() may or may not set feof(), we have to do this whole delayed check acrobatics + if (this->eofNextTime && this->n == 0) + this->eof = true; if (this->eof || this->error) return false; // otherwise process this last chunk of the file From 8b35ab973daca2bfeb69c44ab010e89484df43b1 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Thu, 24 May 2018 16:11:58 -0400 Subject: [PATCH 06/30] Simplification through adversity, or, POSIX is not as portable as it would like :D It still works, though! --- windows/tools/hresultwrap.cpp | 81 +++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 32 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index cdb78040..9fa92072 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -1,38 +1,59 @@ // 21 may 2018 +#ifdef _WIN32 +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 +#include +#include +#define openfunc _open +#define openflags (_O_RDONLY | _O_BINARY) +#define openmode (_S_IREAD) +#define readfunc _read +#define readtype int +#define closefunc _close +#else +#include +#include +#define openfunc open +#define openflags (O_RDONLY) +#define openmode 0644 +#define readfunc read +#define readtype ssize_t +#define closefunc close +#endif #include #include #include +#include class Scanner { - FILE *fin; + int fd; char *buf; const char *p; size_t n; std::vector *line; bool eof; - bool eofNextTime; - bool error; + int error; public: - Scanner(FILE *fin); + Scanner(int fd); ~Scanner(void); bool Scan(void); const char *Bytes(void) const; size_t Len(void) const; - bool Error(void) const; + int Error(void) const; }; #define nbuf 1024 -Scanner::Scanner(FILE *fin) +Scanner::Scanner(int fd) { - this->fin = fin; + this->fd = fd; this->buf = new char[nbuf]; this->p = this->buf; this->n = 0; this->line = new std::vector; this->eof = false; - this->error = false; + this->error = 0; } Scanner::~Scanner(void) @@ -43,7 +64,9 @@ Scanner::~Scanner(void) bool Scanner::Scan(void) { - if (this->eof || this->error) + readtype n; + + if (this->eof || this->error != 0) return false; this->line->clear(); for (;;) { @@ -69,24 +92,17 @@ bool Scanner::Scan(void) // otherwise, the buffer was exhausted in the middle of a line, so fall through } // need to refill the buffer - if (this->eofNextTime) { + n = readfunc(this->fd, this->buf, nbuf * sizeof (char)); + if (n < 0) { + this->error = errno; + return false; + } + if (n == 0) { this->eof = true; return false; } - this->n = fread(this->buf, sizeof (char), nbuf, this->fin); - if (this->n < nbuf) { - // TODO what if this->eofNextTime && this->error? the C standard does not expressly disallow this - this->eofNextTime = feof(this->fin) != 0; - this->error = ferror(this->fin) != 0; - // according to various people in irc.freenode.net/##c, feof() followed by fread() can result in ferror(), so we must be sure not to read twice on a feof() - // however, because a partial (nonzero) fread() may or may not set feof(), we have to do this whole delayed check acrobatics - if (this->eofNextTime && this->n == 0) - this->eof = true; - if (this->eof || this->error) - return false; - // otherwise process this last chunk of the file - } this->p = this->buf; + this->n = n; } } @@ -100,7 +116,7 @@ size_t Scanner::Len(void) const return this->line->size(); } -bool Scanner::Error(void) const +int Scanner::Error(void) const { return this->error; } @@ -135,7 +151,8 @@ bool process(const char *line, size_t n, FILE *fout) int main(int argc, char *argv[]) { - FILE *fin = NULL, *fout = NULL; + int fin = -1; + FILE *fout = NULL; Scanner *s = NULL; int ret = 1; @@ -144,9 +161,9 @@ int main(int argc, char *argv[]) return 1; } - fin = fopen(argv[1], "rb"); - if (fin == NULL) { - fprintf(stderr, "error opening %s\n", argv[1]); + fin = openfunc(argv[1], openflags, openmode); + if (fin < 0) { + fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(errno)); goto done; } fout = fopen(argv[2], "wb"); @@ -167,8 +184,8 @@ int main(int argc, char *argv[]) goto done; } } - if (s->Error()) { - fprintf(stderr, "error reading from %s\n", argv[1]); + if (s->Error() != 0) { + fprintf(stderr, "error reading from %s: %s\n", argv[1], strerror(s->Error())); goto done; } @@ -178,7 +195,7 @@ done: delete s; if (fout != NULL) fclose(fout); - if (fin != NULL) - fclose(fin); + if (fin >= 0) + closefunc(fin); return ret; } From 43c2f26de372e37e9747c9140f3c95a41dd5de73 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 25 May 2018 00:33:56 -0400 Subject: [PATCH 07/30] Split Scanner into its own files. --- windows/tools/hresultwrap.cpp | 128 ++-------------------------------- windows/tools/scanner.cpp | 117 +++++++++++++++++++++++++++++++ windows/tools/scanner.hpp | 23 ++++++ 3 files changed, 146 insertions(+), 122 deletions(-) create mode 100644 windows/tools/scanner.cpp create mode 100644 windows/tools/scanner.hpp diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 9fa92072..04daad5f 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -1,125 +1,8 @@ // 21 may 2018 -#ifdef _WIN32 -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 -#include -#include -#define openfunc _open -#define openflags (_O_RDONLY | _O_BINARY) -#define openmode (_S_IREAD) -#define readfunc _read -#define readtype int -#define closefunc _close -#else -#include -#include -#define openfunc open -#define openflags (O_RDONLY) -#define openmode 0644 -#define readfunc read -#define readtype ssize_t -#define closefunc close -#endif #include #include #include -#include - -class Scanner { - int fd; - char *buf; - const char *p; - size_t n; - std::vector *line; - bool eof; - int error; -public: - Scanner(int fd); - ~Scanner(void); - - bool Scan(void); - const char *Bytes(void) const; - size_t Len(void) const; - int Error(void) const; -}; - -#define nbuf 1024 - -Scanner::Scanner(int fd) -{ - this->fd = fd; - this->buf = new char[nbuf]; - this->p = this->buf; - this->n = 0; - this->line = new std::vector; - this->eof = false; - this->error = 0; -} - -Scanner::~Scanner(void) -{ - delete this->line; - delete[] this->buf; -} - -bool Scanner::Scan(void) -{ - readtype n; - - if (this->eof || this->error != 0) - return false; - this->line->clear(); - for (;;) { - if (this->n > 0) { - size_t j; - bool haveline; - - haveline = false; - for (j = 0; j < this->n; j++) - if (this->p[j] == '\n') { - haveline = true; - break; - } - this->line->insert(this->line->end(), this->p, this->p + j); - this->p += j; - this->n -= j; - if (haveline) { - // swallow the \n for the next time through - this->p++; - this->n--; - return true; - } - // otherwise, the buffer was exhausted in the middle of a line, so fall through - } - // need to refill the buffer - n = readfunc(this->fd, this->buf, nbuf * sizeof (char)); - if (n < 0) { - this->error = errno; - return false; - } - if (n == 0) { - this->eof = true; - return false; - } - this->p = this->buf; - this->n = n; - } -} - -const char *Scanner::Bytes(void) const -{ - return this->line->data(); -} - -size_t Scanner::Len(void) const -{ - return this->line->size(); -} - -int Scanner::Error(void) const -{ - return this->error; -} +#include "scanner.hpp" bool generate(const char *line, size_t n, FILE *fout) { @@ -155,15 +38,16 @@ int main(int argc, char *argv[]) FILE *fout = NULL; Scanner *s = NULL; int ret = 1; + int err; if (argc != 3) { fprintf(stderr, "usage: %s infile outfile\n", argv[0]); return 1; } - fin = openfunc(argv[1], openflags, openmode); - if (fin < 0) { - fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(errno)); + err = OpenForScanner(argv[1], &fin); + if (err != 0) { + fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(err)); goto done; } fout = fopen(argv[2], "wb"); @@ -196,6 +80,6 @@ done: if (fout != NULL) fclose(fout); if (fin >= 0) - closefunc(fin); + CloseForScanner(fin); return ret; } diff --git a/windows/tools/scanner.cpp b/windows/tools/scanner.cpp new file mode 100644 index 00000000..3af2ec89 --- /dev/null +++ b/windows/tools/scanner.cpp @@ -0,0 +1,117 @@ +// 21 may 2018 +#ifdef _WIN32 +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 +#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 +#include +#include +#define openfunc _open +#define openflags (_O_RDONLY | _O_BINARY) +#define openmode (_S_IREAD) +#define readfunc _read +#define readtype int +#define closefunc _close +#else +#include +#include +#define openfunc open +#define openflags (O_RDONLY) +#define openmode 0644 +#define readfunc read +#define readtype ssize_t +#define closefunc close +#endif +#include +#include "scanner.hpp" + +#define nbuf 1024 + +Scanner::Scanner(int fd) +{ + this->fd = fd; + this->buf = new char[nbuf]; + this->p = this->buf; + this->n = 0; + this->line = new std::vector; + this->eof = false; + this->error = 0; +} + +Scanner::~Scanner(void) +{ + delete this->line; + delete[] this->buf; +} + +bool Scanner::Scan(void) +{ + readtype n; + + if (this->eof || this->error != 0) + return false; + this->line->clear(); + for (;;) { + if (this->n > 0) { + size_t j; + bool haveline; + + haveline = false; + for (j = 0; j < this->n; j++) + if (this->p[j] == '\n') { + haveline = true; + break; + } + this->line->insert(this->line->end(), this->p, this->p + j); + this->p += j; + this->n -= j; + if (haveline) { + // swallow the \n for the next time through + this->p++; + this->n--; + return true; + } + // otherwise, the buffer was exhausted in the middle of a line, so fall through + } + // need to refill the buffer + n = readfunc(this->fd, this->buf, nbuf * sizeof (char)); + if (n < 0) { + this->error = errno; + return false; + } + if (n == 0) { + this->eof = true; + return false; + } + this->p = this->buf; + this->n = n; + } +} + +const char *Scanner::Bytes(void) const +{ + return this->line->data(); +} + +size_t Scanner::Len(void) const +{ + return this->line->size(); +} + +int Scanner::Error(void) const +{ + return this->error; +} + +int OpenForScanner(const char *filename, int *fd) +{ + *fd = openfunc(filename, openflags, openmode); + if (*fd < 0) + return errno; + return 0; +} + +int CloseForScanner(int fd) +{ + if (closefunc(fd) < 0) + return errno; + return 0; +} diff --git a/windows/tools/scanner.hpp b/windows/tools/scanner.hpp new file mode 100644 index 00000000..0c83c3d6 --- /dev/null +++ b/windows/tools/scanner.hpp @@ -0,0 +1,23 @@ +// 21 may 2018 +#include + +class Scanner { + int fd; + char *buf; + const char *p; + size_t n; + std::vector *line; + bool eof; + int error; +public: + Scanner(int fd); + ~Scanner(void); + + bool Scan(void); + const char *Bytes(void) const; + size_t Len(void) const; + int Error(void) const; +}; + +extern int OpenForScanner(const char *filename, int *fd); +extern int CloseForScanner(int fd); From ca11bf1e42d4ef1080c82b827dcc612e2a28c734 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 25 May 2018 20:25:36 -0400 Subject: [PATCH 08/30] More notes. --- _notes/misc | 3 +++ _notes/windowsHighDPI | 3 +++ 2 files changed, 6 insertions(+) diff --git a/_notes/misc b/_notes/misc index 7eaf7c5c..373f2336 100644 --- a/_notes/misc +++ b/_notes/misc @@ -204,3 +204,6 @@ font1.gif (GIF Image, 424 × 475 pixels) http://www.functionx.com/win32/controls Inskcape’s Hidden Little Feature: Mesh Gradients | OCS-Mag http://www.ocsmag.com/2016/02/27/inskcapes-hidden-little-feature-mesh-gradients/ (near "When you’re done colouring in all the nodes, you may want to drag") https://msdn.microsoft.com/en-us/library/windows/desktop/ms632615(v=vs.85).aspx we need to handle this alongisde WM_CAPTURECHANGED + +https://msdn.microsoft.com/en-us/library/windows/desktop/dn424996%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 +whatever this is seems to have no documentation... it appears to be related to UWP, if not only Store apps... diff --git a/_notes/windowsHighDPI b/_notes/windowsHighDPI index 0f69a507..1e82c3fb 100644 --- a/_notes/windowsHighDPI +++ b/_notes/windowsHighDPI @@ -16,3 +16,6 @@ https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx# https://msdn.microsoft.com/library/windows/desktop/mt843498(v=vs.85).aspx(d=robot)#appendix_c_common_high_dpi_issues https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx#addressing_high_dpi_issues https://msdn.microsoft.com/library/windows/desktop/mt843498(v=vs.85).aspx(d=robot)#addressing_high_dpi_issues + +https://msdn.microsoft.com/en-us/library/windows/desktop/dn302215(v=vs.85).aspx +https://msdn.microsoft.com/en-us/library/windows/desktop/hh802769(v=vs.85).aspx From 472476392c0ae3ffcb35fd2b84a8033d7b0a85fc Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 25 May 2018 21:07:45 -0400 Subject: [PATCH 09/30] Started expanding what were scanner.cpp and scanner.hpp into a more flexible library for tool writing. Also decided to go with separate POSIX and Windows implementations. --- windows/tools/{scanner.cpp => lib.cpp} | 103 ++++++++++++++---------- windows/tools/lib.hpp | 46 +++++++++++ windows/tools/lib_posix.cpp | 106 +++++++++++++++++++++++++ windows/tools/scanner.hpp | 23 ------ 4 files changed, 215 insertions(+), 63 deletions(-) rename windows/tools/{scanner.cpp => lib.cpp} (56%) create mode 100644 windows/tools/lib.hpp create mode 100644 windows/tools/lib_posix.cpp delete mode 100644 windows/tools/scanner.hpp diff --git a/windows/tools/scanner.cpp b/windows/tools/lib.cpp similarity index 56% rename from windows/tools/scanner.cpp rename to windows/tools/lib.cpp index 3af2ec89..01a63907 100644 --- a/windows/tools/scanner.cpp +++ b/windows/tools/lib.cpp @@ -11,33 +11,75 @@ #define readtype int #define closefunc _close #else -#include -#include -#define openfunc open -#define openflags (O_RDONLY) -#define openmode 0644 -#define readfunc read -#define readtype ssize_t -#define closefunc close #endif -#include -#include "scanner.hpp" +#include +#include "lib.hpp" + +class eofError : public Error { +public: + virtual ~eofError(void); + + virtual const char *String(void) const; +}; + +virtual ~eofError::eofError(void) +{ + // do nothing +} + +virtual const char *eofError::String(void) const +{ + return "EOF"; +} + +class shortWriteError : public Error { +public: + virtual ~shortWriteError(void); + + virtual const char *String(void) const; +}; + +virtual ~shortWriteError::shortWriteError(void) +{ + // do nothing +} + +virtual const char *shortWriteError::String(void) const +{ + return "short write"; +} + +Error *NewEOF(void) +{ + return new eofError; +} + +Error *NewErrShortWrite(void) +{ + return new shortWriteError; +} + +bool IsEOF(Error *e) +{ + return typeid (e) == typeid (eofError *); +} #define nbuf 1024 -Scanner::Scanner(int fd) +Scanner::Scanner(ReadCloser *r) { - this->fd = fd; + this->r = r; this->buf = new char[nbuf]; this->p = this->buf; this->n = 0; this->line = new std::vector; - this->eof = false; - this->error = 0; + this->error = NULL; } Scanner::~Scanner(void) { + if (this->err != NULL) + delete this->err; delete this->line; delete[] this->buf; } @@ -46,7 +88,7 @@ bool Scanner::Scan(void) { readtype n; - if (this->eof || this->error != 0) + if (this->err != NULL) return false; this->line->clear(); for (;;) { @@ -72,15 +114,9 @@ bool Scanner::Scan(void) // otherwise, the buffer was exhausted in the middle of a line, so fall through } // need to refill the buffer - n = readfunc(this->fd, this->buf, nbuf * sizeof (char)); - if (n < 0) { - this->error = errno; + this->err = this->r->Read(this->buf, nbuf * sizeof (char), &n); + if (this->err != NULL) return false; - } - if (n == 0) { - this->eof = true; - return false; - } this->p = this->buf; this->n = n; } @@ -96,22 +132,9 @@ size_t Scanner::Len(void) const return this->line->size(); } -int Scanner::Error(void) const +int Scanner::Err(void) const { - return this->error; -} - -int OpenForScanner(const char *filename, int *fd) -{ - *fd = openfunc(filename, openflags, openmode); - if (*fd < 0) - return errno; - return 0; -} - -int CloseForScanner(int fd) -{ - if (closefunc(fd) < 0) - return errno; - return 0; + if (!IsEOF(this->err)) + return this->err; + return NULL; } diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp new file mode 100644 index 00000000..1d9228e9 --- /dev/null +++ b/windows/tools/lib.hpp @@ -0,0 +1,46 @@ +// 21 may 2018 +#include + +class Error { +public: + virtual ~Error(void); + + virtual const char *String(void) const = 0; +}; + +extern Error *NewEOF(void); +extern Error *NewErrShortWrite(void); +extern bool IsEOF(Error *e); + +class ReadCloser { +public: + virtual ~ReadCloser(void); + + virtual Error *Read(void *buf, size_t n, size_t *actual) = 0; +}; + +class WriteCloser { +public: + virtual ~WriteCloser(void); + + virtual Error *Write(void *buf, size_t n) = 0; +}; + +extern Error *OpenRead(const char *filename, ReadCloser **r); + +class Scanner { + ReadCloser *r; + char *buf; + const char *p; + size_t n; + std::vector *line; + Error *err; +public: + Scanner(ReadCloser *r); + ~Scanner(void); + + bool Scan(void); + const char *Bytes(void) const; + size_t Len(void) const; + Error *Err(void) const; +}; diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp new file mode 100644 index 00000000..9c0e9347 --- /dev/null +++ b/windows/tools/lib_posix.cpp @@ -0,0 +1,106 @@ +// 25 may 2018 +#include +#include +#include +#include +#include "lib.hpp" + +class posixError : public Error { + int error; +public: + posixError(int error); + virtual ~posixError(void); + + virtual const char *String(void) const; +}; + +posixError::posixError(int error) +{ + this->error = error; +} + +virtual posixError::~posixError(void) +{ + // do nothing +} + +virtual const char *posixError::String(void) const +{ + return strerror(this->error); +} + +class posixReadCloser : public ReadCloser { + int fd; +public: + posixReadCloser(int fd); + virtual ~posixReadCloser(void); + + virtual Error *Read(void *buf, size_t n, size_t *actual); +}; + +posixReadCloser::posixReadCloser(int fd) +{ + this->fd = fd; +} + +virtual posixReadCloser::~posixReadCloser(void) +{ + close(this->fd); +} + +virtual Error *posixReadCloser::Read(void *buf, size_t n, size_t *actual) +{ + ssize_t ret; + + *actual = 0; + ret = read(this->fd, buf, n); + if (ret < 0) + return new posixError(errno); + if (ret == 0) + return NewEOF(void); + *actual = ret; + return NULL; +} + +class posixWriteCloser : public WriteCloser { + int fd; +public: + posixWriteCloser(int fd); + virtual ~posixWriteCloser(void); + + virtual Error *Write(void *buf, size_t n, size_t *actual); +}; + +posixWriteCloser::posixWriteCloser(int fd) +{ + this->fd = fd; +} + +virtual posixWriteCloser::~posixWriteCloser(void) +{ + close(this->fd); +} + +virtual Error *posixWriteCloser::Write(void *buf, size_t n) +{ + ssize_t ret; + + ret = write(this->fd, buf, n); + if (ret < 0) + return new posixError(errno); + if (ret != n) + return NewErrShortWrite(void); + return NULL; +} + +Error *OpenRead(const char *filename, ReadCloser **r) +{ + int fd; + + *r = NULL; + fd = open(filename, O_RDONLY, 0644); + if (fd < 0) + return new posixError(errno); + *r = new posixReadCloser(fd); + return NULL; +} diff --git a/windows/tools/scanner.hpp b/windows/tools/scanner.hpp deleted file mode 100644 index 0c83c3d6..00000000 --- a/windows/tools/scanner.hpp +++ /dev/null @@ -1,23 +0,0 @@ -// 21 may 2018 -#include - -class Scanner { - int fd; - char *buf; - const char *p; - size_t n; - std::vector *line; - bool eof; - int error; -public: - Scanner(int fd); - ~Scanner(void); - - bool Scan(void); - const char *Bytes(void) const; - size_t Len(void) const; - int Error(void) const; -}; - -extern int OpenForScanner(const char *filename, int *fd); -extern int CloseForScanner(int fd); From a6634f775b95b6be84974f9b6788c6f3ff67af98 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Fri, 25 May 2018 21:17:04 -0400 Subject: [PATCH 10/30] Minor style fretting --- windows/tools/lib_posix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp index 9c0e9347..30943a34 100644 --- a/windows/tools/lib_posix.cpp +++ b/windows/tools/lib_posix.cpp @@ -1,8 +1,8 @@ // 25 may 2018 -#include -#include #include #include +#include +#include #include "lib.hpp" class posixError : public Error { From a07727515fc15576c67ea5cbda128d6496749e3d Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 26 May 2018 16:56:53 -0400 Subject: [PATCH 11/30] Updated hresultwrap to use lib.cpp, fixing errors along the way. --- windows/tools/hresultwrap.cpp | 23 ++++++++++++----------- windows/tools/lib.cpp | 17 +++++++++-------- windows/tools/lib.hpp | 6 +++--- windows/tools/lib_posix.cpp | 20 ++++++++++---------- 4 files changed, 34 insertions(+), 32 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 04daad5f..e8675937 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -1,8 +1,7 @@ // 21 may 2018 #include #include -#include -#include "scanner.hpp" +#include "lib.hpp" bool generate(const char *line, size_t n, FILE *fout) { @@ -34,20 +33,20 @@ bool process(const char *line, size_t n, FILE *fout) int main(int argc, char *argv[]) { - int fin = -1; + ReadCloser *fin = NULL; FILE *fout = NULL; Scanner *s = NULL; int ret = 1; - int err; + Error *err = NULL; if (argc != 3) { fprintf(stderr, "usage: %s infile outfile\n", argv[0]); return 1; } - err = OpenForScanner(argv[1], &fin); - if (err != 0) { - fprintf(stderr, "error opening %s: %s\n", argv[1], strerror(err)); + err = OpenRead(argv[1], &fin); + if (err != NULL) { + fprintf(stderr, "error opening %s: %s\n", argv[1], err->String()); goto done; } fout = fopen(argv[2], "wb"); @@ -68,8 +67,8 @@ int main(int argc, char *argv[]) goto done; } } - if (s->Error() != 0) { - fprintf(stderr, "error reading from %s: %s\n", argv[1], strerror(s->Error())); + if (s->Err() != 0) { + fprintf(stderr, "error reading from %s: %s\n", argv[1], s->Err()->String()); goto done; } @@ -79,7 +78,9 @@ done: delete s; if (fout != NULL) fclose(fout); - if (fin >= 0) - CloseForScanner(fin); + if (fin != NULL) + delete fin; + if (err != NULL) + delete err; return ret; } diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index 01a63907..b548f3c5 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -22,12 +22,12 @@ public: virtual const char *String(void) const; }; -virtual ~eofError::eofError(void) +eofError::~eofError(void) { // do nothing } -virtual const char *eofError::String(void) const +const char *eofError::String(void) const { return "EOF"; } @@ -39,12 +39,12 @@ public: virtual const char *String(void) const; }; -virtual ~shortWriteError::shortWriteError(void) +shortWriteError::~shortWriteError(void) { // do nothing } -virtual const char *shortWriteError::String(void) const +const char *shortWriteError::String(void) const { return "short write"; } @@ -61,7 +61,8 @@ Error *NewErrShortWrite(void) bool IsEOF(Error *e) { - return typeid (e) == typeid (eofError *); + // typeid does not work directly with pointers, alas (see https://stackoverflow.com/questions/4202877/typeid-for-polymorphic-types) + return typeid (*e) == typeid (eofError); } #define nbuf 1024 @@ -73,7 +74,7 @@ Scanner::Scanner(ReadCloser *r) this->p = this->buf; this->n = 0; this->line = new std::vector; - this->error = NULL; + this->err = NULL; } Scanner::~Scanner(void) @@ -86,7 +87,7 @@ Scanner::~Scanner(void) bool Scanner::Scan(void) { - readtype n; + size_t n; if (this->err != NULL) return false; @@ -132,7 +133,7 @@ size_t Scanner::Len(void) const return this->line->size(); } -int Scanner::Err(void) const +Error *Scanner::Err(void) const { if (!IsEOF(this->err)) return this->err; diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index 1d9228e9..b8b8f3bf 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -3,7 +3,7 @@ class Error { public: - virtual ~Error(void); + virtual ~Error(void) = default; virtual const char *String(void) const = 0; }; @@ -14,14 +14,14 @@ extern bool IsEOF(Error *e); class ReadCloser { public: - virtual ~ReadCloser(void); + virtual ~ReadCloser(void) = default; virtual Error *Read(void *buf, size_t n, size_t *actual) = 0; }; class WriteCloser { public: - virtual ~WriteCloser(void); + virtual ~WriteCloser(void) = default; virtual Error *Write(void *buf, size_t n) = 0; }; diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp index 30943a34..a743af9b 100644 --- a/windows/tools/lib_posix.cpp +++ b/windows/tools/lib_posix.cpp @@ -19,12 +19,12 @@ posixError::posixError(int error) this->error = error; } -virtual posixError::~posixError(void) +posixError::~posixError(void) { // do nothing } -virtual const char *posixError::String(void) const +const char *posixError::String(void) const { return strerror(this->error); } @@ -43,12 +43,12 @@ posixReadCloser::posixReadCloser(int fd) this->fd = fd; } -virtual posixReadCloser::~posixReadCloser(void) +posixReadCloser::~posixReadCloser(void) { close(this->fd); } -virtual Error *posixReadCloser::Read(void *buf, size_t n, size_t *actual) +Error *posixReadCloser::Read(void *buf, size_t n, size_t *actual) { ssize_t ret; @@ -57,7 +57,7 @@ virtual Error *posixReadCloser::Read(void *buf, size_t n, size_t *actual) if (ret < 0) return new posixError(errno); if (ret == 0) - return NewEOF(void); + return NewEOF(); *actual = ret; return NULL; } @@ -68,7 +68,7 @@ public: posixWriteCloser(int fd); virtual ~posixWriteCloser(void); - virtual Error *Write(void *buf, size_t n, size_t *actual); + virtual Error *Write(void *buf, size_t n); }; posixWriteCloser::posixWriteCloser(int fd) @@ -76,20 +76,20 @@ posixWriteCloser::posixWriteCloser(int fd) this->fd = fd; } -virtual posixWriteCloser::~posixWriteCloser(void) +posixWriteCloser::~posixWriteCloser(void) { close(this->fd); } -virtual Error *posixWriteCloser::Write(void *buf, size_t n) +Error *posixWriteCloser::Write(void *buf, size_t n) { ssize_t ret; ret = write(this->fd, buf, n); if (ret < 0) return new posixError(errno); - if (ret != n) - return NewErrShortWrite(void); + if (((size_t) ret) != n) + return NewErrShortWrite(); return NULL; } From 8f5eba45bd0377b68e79292bc77c9d02644270bc Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 26 May 2018 17:42:11 -0400 Subject: [PATCH 12/30] Added more support for writing hresultwrap itself. There is probably a more C++-y way to write all this :| If only I could use Go... --- windows/tools/hresultwrap.cpp | 16 +++++++--- windows/tools/lib.cpp | 58 +++++++++++++++++++++++++++++++++++ windows/tools/lib.hpp | 16 ++++++++++ windows/tools/lib_posix.cpp | 12 ++++++++ 4 files changed, 97 insertions(+), 5 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index e8675937..35be883d 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -6,13 +6,19 @@ bool generate(const char *line, size_t n, FILE *fout) { std::vector genout; + std::vector *tokens; + std::vector::const_iterator i; size_t nw; - genout.push_back('/'); - genout.push_back('/'); - genout.push_back(' '); - genout.insert(genout.end(), line, line + n); - genout.push_back('\n'); + tokens = TokenizeWhitespace(line, n); + for (i = tokens->begin(); i < tokens->end(); i++) { + genout.push_back('/'); + genout.push_back('/'); + genout.push_back(' '); + AppendSlice(&genout, *i); + genout.push_back('\n'); + } + FreeTokenized(tokens); genout.push_back('\n'); nw = fwrite(genout.data(), sizeof (char), genout.size(), fout); diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index b548f3c5..a881cf7e 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -13,6 +13,7 @@ #else #endif #include +#include #include "lib.hpp" class eofError : public Error { @@ -65,6 +66,11 @@ bool IsEOF(Error *e) return typeid (*e) == typeid (eofError); } +Error *WriteVector(WriteCloser *w, std::vector *v) +{ + return w->Write(v->data(), v->size()); +} + #define nbuf 1024 Scanner::Scanner(ReadCloser *r) @@ -139,3 +145,55 @@ Error *Scanner::Err(void) const return this->err; return NULL; } + +Slice::Slice(const char *p, size_t n) +{ + this->p = p; + this->n = n; +} + +const char *Slice::Data(void) const +{ + return this->p; +} + +size_t Slice::Len(void) const +{ + return this->n; +} + +std::vector *TokenizeWhitespace(const char *buf, size_t n) +{ + std::vector *ret; + const char *p, *q; + const char *end; + + ret = new std::vector; + p = buf; + end = buf + n; + while (p < end) { + if (*p == ' ' || *p == '\t') { + p++; + continue; + } + for (q = p; q < end; q++) + if (*q == ' ' || *q == '\t') + break; + ret->push_back(new Slice(p, q - p)); + p = q; + } + return ret; +} + +void FreeTokenized(std::vector *v) +{ + std::for_each(v->begin(), v->end(), [](Slice *s) { + delete s; + }); + delete v; +} + +void AppendSlice(std::vector *v, Slice *s) +{ + v->insert(v->end(), s->Data(), s->Data() + s->Len()); +} diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index b8b8f3bf..d1f9ca50 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -27,6 +27,8 @@ public: }; extern Error *OpenRead(const char *filename, ReadCloser **r); +extern Error *CreateWrite(const char *filename, WriteCloser **w); +extern Error *WriteVector(WriteCloser *w, std::vector *v); class Scanner { ReadCloser *r; @@ -44,3 +46,17 @@ public: size_t Len(void) const; Error *Err(void) const; }; + +class Slice { + const char *p; + size_t n; +public: + Slice(const char *p, size_t n); + + const char *Data(void) const; + size_t Len(void) const; +}; + +extern std::vector *TokenizeWhitespace(const char *buf, size_t n); +extern void FreeTokenized(std::vector *v); +extern void AppendSlice(std::vector *v, Slice *s); diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp index a743af9b..528cc35e 100644 --- a/windows/tools/lib_posix.cpp +++ b/windows/tools/lib_posix.cpp @@ -104,3 +104,15 @@ Error *OpenRead(const char *filename, ReadCloser **r) *r = new posixReadCloser(fd); return NULL; } + +Error *CreateWrite(const char *filename, WriteCloser **w) +{ + int fd; + + *w = NULL; + fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (fd < 0) + return new posixError(errno); + *w = new posixWriteCloser(fd); + return NULL; +} From ef9e08d4ad3e941f0caa4bec7ebf0ce6983ca3d2 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 26 May 2018 19:40:55 -0400 Subject: [PATCH 13/30] Started assembling the input file to this hresult utility. --- windows/tools/a | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 windows/tools/a diff --git a/windows/tools/a b/windows/tools/a new file mode 100644 index 00000000..fd4ff220 --- /dev/null +++ b/windows/tools/a @@ -0,0 +1,70 @@ +@BOOL UnregisterClassW LPCWSTR className HINSTANCE hInstance == 0 +@*HWND CreateWindowExW DWORD exstyle LPCWSTR className LPCWSTR title DWORD style int x int y int width int height HWND parent HMENU menu HINSTANCE hInstance LPVOID lpParam == NULL +@BOOL DestroyWindow HWND hwnd == 0 +@BOOL UpdateWindow HWND hwnd == 0 +@BOOL AdustWindowRectEx LPRECT r DWORD style BOOL hasMenu DWORD exStyle == 0 + +@*BOOL GetMessageW LPMSG msg HWND hwnd UINT minMsg UINT maxMsg < 0 +@BOOL PostMessageW HWND hwnd UINT uMsg WPARAM wParam LPARAM lParam == 0 +@UINT_PTR SetTimer HWND hwnd UINT_PTR id UINT time TIMERPROC proc == 0 +@BOOL KillTimer HWND hwnd UINT_PTR id == 0 + +@int GetWindowTextW HWND hwnd LPWSTR str int n == 0 +@BOOL SetWindowTextW HWND hwnd LPCWSTR str == 0 +@BOOL SetWindowPos HWND hwnd HWND insertAfter int x int y int cx int cy UINT flags == 0 +$typedef WINDOWPLACEMENT *uiprivLPWINDOWPLACEMENT; +@BOOL GetWindowPlacement HWND hwnd uiprivLPWWINDOWPLACEMENT wp == 0 +$typedef const WINDOWPLACEMENT *uiprivLPCWINDOWPLACEMENT; +@BOOL SetWindowPlacement HWND hwnd uiprivLPCWINDOWPLACEMENT wp == 0 +@HWND SetParent HWND hwnd HWND newParent == NULL +@BOOL GetClientRect HWND hwnd LPRECT r == 0 +@BOOL GetWindowRect HWND hwnd LPRECT r == 0 +@int GetClassNameW HWND hwnd LPWSTR name int n == 0 + +@BOOL SetWindowSubclass HWND hwnd SUBCLASSPROC proc UINT_PTR id DWORD_PTR dwRefData == FALSE +@BOOL RemoveWindowSubclass HWND hwnd SUBCLASSPROC proc UINT_PTR id == FALSE + +@*HWND CreateDialogIndirectParamW HINSTANCE hInstance LPCDLGTEMPLATE dialog HWND parent DLGPROC proc LPARAM param == NULL +// note: this gives dialogs in libui the condition that they must NOT call uiprivTODOEndDialog() with a negative result code +@*INT_PTR DialogBoxIndirectParamW HINSTANCE hInstance LPCDLGTEMPLATE dialog HWND parent DLGPROC proc LPARAM param < 0 +@BOOL EndDialog HWND hdlg INT_PTR result == 0 +@*HWND GetDlgItem HWND hdlg int id == NULL + +@*HMENU CreateMenu == NULL +@*HMENU CreatePopupMenu == NULL +@BOOL AppendMenuW HMENU menu UINT flags UINT_PTR id LPCWSTR text == 0 +@BOOL SetMenu HWND hwnd HMENU menu == 0 +@BOOL GetMenuItemInfoW HMENU menu UINT item BOOL byPosition LPMENUITEMINFO info == 0 +@BOOL SetMenuItemInfoW HMENU menu UINT item BOOL byPosition LPMENUITEMINFO info == 0 + +@*HDC BeginPaint HWND hwnd LPPAINTSTRUCT ps == NULL +@*HDC GetDC HWND hwnd == NULL +@int ReleaseDC HWND hwnd HDC dc == 0 +@*HDC CreateCompatibleDC HDC dc == NULL +@BOOL DeleteDC HDC dc == 0 +$typedef const RECT *uiprivLPCRECT; +@BOOL InvalidateRect HWND hwnd uiprivLPCRECT r BOOL erase == 0 +@BOOL ValidateRect HWND hwnd uiprivLPCRECT r == 0 + +@*HBITMAP CreateCompatibleBitmap HDC dc int width int height == NULL +@*HBRUSH CreatePatternBrush HBITMAP bitmap == NULL +@BOOL DeleteObject HGDIOBJ obj == 0 + +@BOOL SetBrushOrgEx HDC dc int x int y LPPOINT prev == 0 +@int SetBkMode HDC dc int mode == 0 +@BOOL BitBlt HDC dest int destX int destY int destWidth int destHeight HDC src int srcX int srcY DWORD op == 0 + +@BOOL GetTextMetricsW HDC dc LPTEXTMETRIC tm == 0 +@BOOL APIENTRY GetTextExtentPoint32W HDC dc LPCWSTR str int n LPSIZE size == 0 + +@BOOL ReleaseCapture == 0 +@BOOL _TrackMouseEvent LPTRACKMOUSEEVENT tme == 0 + +@BOOL GetScrollInfo HWND hwnd int bar LPSCROLLINFO si == 0 + +@BOOL SystemParametersInfoW UINT action UINT param PVOID v UINT winini == 0 +@BOOL GetMonitorInfoW HMONITOR monitor LPMONITORINFO info == 0 + +@*int GetLocaleInfoEx LPCWSTR name LCTYPE type LPWSTR buf int n == 0 + +@BOOL UnhookWindowsHookEx HHOOK hook == 0 From 481e1e30bbf8db3e469291c8083c2439746a783c Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 26 May 2018 20:09:16 -0400 Subject: [PATCH 14/30] And updated hresultwrap to produce signatures. Man this is so un-C++-y it actually feels like I'm doing it wrong... --- windows/tools/hresultwrap.cpp | 72 +++++++++++++++++++++++++++++++---- windows/tools/lib.cpp | 6 +++ windows/tools/lib.hpp | 2 + 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 35be883d..4fda9236 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -1,23 +1,81 @@ // 21 may 2018 #include #include +#include #include "lib.hpp" +struct item { + Slice *name; + Slice *callingConvention; + Slice **params; + size_t nParams; + Slice *returns; + bool keepReturn; + Slice *cond[2]; +}; + bool generate(const char *line, size_t n, FILE *fout) { std::vector genout; std::vector *tokens; - std::vector::const_iterator i; + size_t i, j; + struct item item; size_t nw; tokens = TokenizeWhitespace(line, n); - for (i = tokens->begin(); i < tokens->end(); i++) { - genout.push_back('/'); - genout.push_back('/'); - genout.push_back(' '); - AppendSlice(&genout, *i); - genout.push_back('\n'); + + memset(&item, 0, sizeof (struct item)); + i = 0; + item.returns = tokens->at(i); + if (item.returns->Data()[0] == '*') { + item.returns = new Slice(item.returns->Data() + 1, item.returns->Len() - 1); + item.keepReturn = true; } + i++; + if (tokens->size() % 2 == 1) { + item.callingConvention = tokens->at(i); + i++; + } + item.name = tokens->at(i); + i++; + item.cond[0] = tokens->at(tokens->size() - 2); + item.cond[1] = tokens->at(tokens->size() - 1); + item.nParams = (tokens->size() - 2) - i; + item.params = new Slice *[item.nParams]; + for (j = 0; j < item.nParams; j++) { + item.params[j] = tokens->at(i); + i++; + } + + AppendString(&genout, "HRESULT "); + if (item.callingConvention != NULL) { + AppendSlice(&genout, item.callingConvention); + genout.push_back(' '); + } + AppendSlice(&genout, item.name); + genout.push_back('('); + for (i = 0; i < item.nParams; i += 2) { + AppendSlice(&genout, item.params[i]); + genout.push_back(' '); + AppendSlice(&genout, item.params[i + 1]); + genout.push_back(','); + genout.push_back(' '); + } + if (item.keepReturn) { + AppendSlice(&genout, item.returns); + AppendString(&genout, " *ret"); + } else if (item.nParams != 0) { + // remove the trailing comma and space + genout.pop_back(); + genout.pop_back(); + } else + AppendString(&genout, "void"); + genout.push_back(')'); + genout.push_back('\n'); + + delete[] item.params; + if (item.keepReturn) + delete item.returns; FreeTokenized(tokens); genout.push_back('\n'); diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index a881cf7e..7a05e83d 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -14,6 +14,7 @@ #endif #include #include +#include #include "lib.hpp" class eofError : public Error { @@ -146,6 +147,11 @@ Error *Scanner::Err(void) const return NULL; } +void AppendString(std::vector *v, const char *str) +{ + v->insert(v->end(), str, str + strlen(str)); +} + Slice::Slice(const char *p, size_t n) { this->p = p; diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index d1f9ca50..f05f8e27 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -47,6 +47,8 @@ public: Error *Err(void) const; }; +extern void AppendString(std::vector *v, const char *str); + class Slice { const char *p; size_t n; From 8231bd337ffd0622118651fa7f6cb11eb7f476d2 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 15:36:16 -0400 Subject: [PATCH 15/30] Built a new ByteSlice interface in lib.cpp that will keep shuffling the bytes around much nicer. I'll change everything to use it next. --- windows/tools/lib.cpp | 195 ++++++++++++++++++++++++++++++++++++++++++ windows/tools/lib.hpp | 29 +++++++ 2 files changed, 224 insertions(+) diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index 7a05e83d..becdf661 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -13,8 +13,10 @@ #else #endif #include +#include #include #include +#include #include "lib.hpp" class eofError : public Error { @@ -67,6 +69,199 @@ bool IsEOF(Error *e) return typeid (*e) == typeid (eofError); } +namespace { + +struct sliceAlloc { + char *b; + size_t n; + uintmax_t refcount; +}; + +std::map sliceAllocs; + +char *sliceAlloc(size_t n) +{ + struct sliceAlloc sa; + + sa.b = new char[n]; + sa.n = n; + sa.refcount = 1; + sliceAllocs[(uintptr_t) (sa.b)] = sa; + return sa.b; +} + +uintptr_t sliceLookup(char *b) +{ + return *(sliceAllocs.lower_bound((uintptr_t) b)); +} + +void sliceRetain(char *b) +{ + if (b == NULL) + return; + sliceAllocs[sliceLookup(b)].refcount++; +} + +void sliceRelease(char *b) +{ + uintptr_t key; + + if (b == NULL) + return; + key = sliceLookup(b); + sliceAllocs[key].refcount--; + if (sliceAllocs[key].refcount == 0) { + delete[] sliceAllocs[key].b; + sliceAllocs.erase(key); + } +} + +} + +ByteSlice::ByteSlice(void) +{ + this->data = NULL; + this->len = 0; + this->cap = 0; +} + +ByteSlice::ByteSlice(const ByteSlice &b) +{ + this->data = b.data; + sliceRetain(this->data); + this->len = b.len; + this->cap = b.cap; +} + +ByteSlice::ByteSlice(ByteSlice &&b) +{ + this->data = b.data; + b.data = NULL; + this->len = b.len; + b.len = 0; + this->cap = b.cap; + b.cap = 0; +} + +ByteSlice::ByteSlice(const char *b, size_t n) +{ + this->data = sliceAlloc(n); + memcpy(this->data, b, n * sizeof (char)); + this->len = n; + this->cap = n; +} + +ByteSlice::ByteSlice(size_t len, size_t cap) +{ + this->data = sliceAlloc(cap); + memset(this->data, 0, len * sizeof (char)); + this->len = len; + this->cap = cap; +} + +ByteSlice::~ByteSlice(void) +{ + sliceRelease(this->data); +} + +ByteSlice &ByteSlice::operator=(const ByteSlice &b) +{ + this->data = b.data; + sliceRetain(this->data); + this->len = b.len; + this->cap = b.cap; + return *this; +} + +ByteSlice &ByteSlice::operator=(ByteSlice &&b) +{ + this->data = b.data; + b.data = NULL; + this->len = b.len; + b.len = 0; + this->cap = b.cap; + b.cap = 0; + return *this; +} + +ByteSlice ByteSlice::Slice(size_t start, size_t end) +{ + ByteSlice b; + + b.data = this->data + start; + sliceRetain(b.data); + b.len = end - start; + b.cap = this->cap - start; + return b; +} + +char *ByteSlice::Data(void) +{ + return this->data; +} + +const char *ByteSlice::Data(void) const +{ + return this->data; +} + +size_t ByteSlice::Len(void) const +{ + return this->len; +} + +size_t ByteSlice::Cap(void) const +{ + return this->cap; +} + +ByteSlice ByteSlice::Slice(size_t start, size_t end) +{ + ByteSlice b; + + b.data = this->data + start; + sliceRetain(b.data); + b.len = end - start; + b.cap = this->cap - start; + return b; +} + +ByteSlice ByteSlice::Append(const char *b, size_t n) +{ + ByteSlice s; + + if (this->len + n < this->cap) { + s.data = this->data; + sliceRetain(s.data); + s.len = this->len + n; + s.cap = this->cap; + memcpy(s.data + this->len, b, n * sizeof (char)); + return s; + } + s.data = sliceAlloc(this->len + n); + memcpy(s.data, this->data, this->len * sizeof (char)); + memcpy(s.data + this->len, b, n * sizeof (char)); + s.len = this->len + n; + s.cap = this->len + n; + return s; +} + +ByteSlice ByteSlice::Append(const ByteSlice &b) +{ + return this->Append(b.data, b.len); +} + +void ByteSlice::CopyFrom(const char *b, size_t n) +{ + n = std::min(this->len, n); + memcpy(this->data, b, n); +} + +void ByteSlice::CopyFrom(const ByteSlice &b) +{ + this->CopyFrom(b.data, b.len); +} + Error *WriteVector(WriteCloser *w, std::vector *v) { return w->Write(v->data(), v->size()); diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index f05f8e27..68220baf 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -12,6 +12,35 @@ extern Error *NewEOF(void); extern Error *NewErrShortWrite(void); extern bool IsEOF(Error *e); +class ByteSlice { + char *data; + size_t len; + size_t cap; +public: + ByteSlice(void); // default constructor; equivalent to Go's nil slice + ByteSlice(const ByteSlice &b); // copy constructor + ByteSlice(ByteSlice &&b); // move constructor; sets b to ByteSlice() + ByteSlice(const char *b, size_t n); + ByteSlice(size_t len, size_t cap); + ~ByteSlice(void); + + // note: copy assignment does not use copy-and-swap because I get neither copy-and-swap nor ADL public friend swap functions (https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom, https://stackoverflow.com/questions/5695548/public-friend-swap-member-function) + // (and also [14:55:04] i don't see why you'd need swap-on-copy semantics for anything if you're really just trying to make copy assignments create two references to the same memory) + ByteSlice &operator=(const ByteSlice &b); // copy assignment + ByteSlice &operator=(ByteSlice &&b); // move assignment; sets b to ByteSlice() + + char *Data(void); + const char *Data(void) const; + size_t Len(void) const; + size_t Cap(void) const; + + ByteSlice Slice(size_t start, size_t end); + ByteSlice Append(const char *b, size_t n); + ByteSlice Append(const ByteSlice &b); + void CopyFrom(const char *b, size_t n); + void CopyFrom(const ByteSlice &b); +}; + class ReadCloser { public: virtual ~ReadCloser(void) = default; From 4a7e7ed9839a5165cbd2fc33726be17ce9ad67d6 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 15:50:00 -0400 Subject: [PATCH 16/30] Rewrote the library to use ByteSlice. --- windows/tools/lib.cpp | 100 +++++++++--------------------------- windows/tools/lib.hpp | 29 +++-------- windows/tools/lib_posix.cpp | 18 +++---- 3 files changed, 41 insertions(+), 106 deletions(-) diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index becdf661..36bf174d 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -92,7 +92,7 @@ char *sliceAlloc(size_t n) uintptr_t sliceLookup(char *b) { - return *(sliceAllocs.lower_bound((uintptr_t) b)); + return sliceAllocs.lower_bound((uintptr_t) b)->first; } void sliceRetain(char *b) @@ -184,17 +184,6 @@ ByteSlice &ByteSlice::operator=(ByteSlice &&b) return *this; } -ByteSlice ByteSlice::Slice(size_t start, size_t end) -{ - ByteSlice b; - - b.data = this->data + start; - sliceRetain(b.data); - b.len = end - start; - b.cap = this->cap - start; - return b; -} - char *ByteSlice::Data(void) { return this->data; @@ -251,6 +240,11 @@ ByteSlice ByteSlice::Append(const ByteSlice &b) return this->Append(b.data, b.len); } +ByteSlice ByteSlice::AppendString(const char *str) +{ + return this->Append(str, strlen(str)); +} + void ByteSlice::CopyFrom(const char *b, size_t n) { n = std::min(this->len, n); @@ -262,11 +256,6 @@ void ByteSlice::CopyFrom(const ByteSlice &b) this->CopyFrom(b.data, b.len); } -Error *WriteVector(WriteCloser *w, std::vector *v) -{ - return w->Write(v->data(), v->size()); -} - #define nbuf 1024 Scanner::Scanner(ReadCloser *r) @@ -275,7 +264,7 @@ Scanner::Scanner(ReadCloser *r) this->buf = new char[nbuf]; this->p = this->buf; this->n = 0; - this->line = new std::vector; + this->line = ByteSlice(0, nbuf); this->err = NULL; } @@ -283,7 +272,6 @@ Scanner::~Scanner(void) { if (this->err != NULL) delete this->err; - delete this->line; delete[] this->buf; } @@ -293,7 +281,7 @@ bool Scanner::Scan(void) if (this->err != NULL) return false; - this->line->clear(); + this->line = this->line.Slice(0, 0); for (;;) { if (this->n > 0) { size_t j; @@ -305,7 +293,7 @@ bool Scanner::Scan(void) haveline = true; break; } - this->line->insert(this->line->end(), this->p, this->p + j); + this->line = this->line.Append(this->p, j); this->p += j; this->n -= j; if (haveline) { @@ -325,14 +313,9 @@ bool Scanner::Scan(void) } } -const char *Scanner::Bytes(void) const +ByteSlice Scanner::Bytes(void) const { - return this->line->data(); -} - -size_t Scanner::Len(void) const -{ - return this->line->size(); + return this->line; } Error *Scanner::Err(void) const @@ -342,59 +325,24 @@ Error *Scanner::Err(void) const return NULL; } -void AppendString(std::vector *v, const char *str) +std::vector ByteSliceFields(ByteSlice s) { - v->insert(v->end(), str, str + strlen(str)); -} + std::vector ret; + const char *data; + size_t i, j; -Slice::Slice(const char *p, size_t n) -{ - this->p = p; - this->n = n; -} - -const char *Slice::Data(void) const -{ - return this->p; -} - -size_t Slice::Len(void) const -{ - return this->n; -} - -std::vector *TokenizeWhitespace(const char *buf, size_t n) -{ - std::vector *ret; - const char *p, *q; - const char *end; - - ret = new std::vector; - p = buf; - end = buf + n; - while (p < end) { - if (*p == ' ' || *p == '\t') { - p++; + data = s.Data(); + i = 0; + while (i < s.Len()) { + if (data[i] == ' ' || data[i] == '\t') { + i++; continue; } - for (q = p; q < end; q++) - if (*q == ' ' || *q == '\t') + for (j = i + 1; j < s.Len(); j++) + if (data[j] == ' ' || data[j] == '\t') break; - ret->push_back(new Slice(p, q - p)); - p = q; + ret.push_back(s.Slice(i, j)); + i = j; } return ret; } - -void FreeTokenized(std::vector *v) -{ - std::for_each(v->begin(), v->end(), [](Slice *s) { - delete s; - }); - delete v; -} - -void AppendSlice(std::vector *v, Slice *s) -{ - v->insert(v->end(), s->Data(), s->Data() + s->Len()); -} diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index 68220baf..2de42036 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -12,6 +12,8 @@ extern Error *NewEOF(void); extern Error *NewErrShortWrite(void); extern bool IsEOF(Error *e); +// super lightweight (can be passed by value without any data being copied) wrapper around an array of bytes that can be sliced further without copying (std::vector can't do that easily) +// this is modelled after Go's slices class ByteSlice { char *data; size_t len; @@ -37,6 +39,7 @@ public: ByteSlice Slice(size_t start, size_t end); ByteSlice Append(const char *b, size_t n); ByteSlice Append(const ByteSlice &b); + ByteSlice AppendString(const char *str); void CopyFrom(const char *b, size_t n); void CopyFrom(const ByteSlice &b); }; @@ -45,49 +48,33 @@ class ReadCloser { public: virtual ~ReadCloser(void) = default; - virtual Error *Read(void *buf, size_t n, size_t *actual) = 0; + virtual Error *Read(ByteSlice b, size_t *n) = 0; }; class WriteCloser { public: virtual ~WriteCloser(void) = default; - virtual Error *Write(void *buf, size_t n) = 0; + virtual Error *Write(const ByteSlice b) = 0; }; extern Error *OpenRead(const char *filename, ReadCloser **r); extern Error *CreateWrite(const char *filename, WriteCloser **w); -extern Error *WriteVector(WriteCloser *w, std::vector *v); class Scanner { ReadCloser *r; char *buf; const char *p; size_t n; - std::vector *line; + ByteSlice line; Error *err; public: Scanner(ReadCloser *r); ~Scanner(void); bool Scan(void); - const char *Bytes(void) const; - size_t Len(void) const; + ByteSlice Bytes(void) const; Error *Err(void) const; }; -extern void AppendString(std::vector *v, const char *str); - -class Slice { - const char *p; - size_t n; -public: - Slice(const char *p, size_t n); - - const char *Data(void) const; - size_t Len(void) const; -}; - -extern std::vector *TokenizeWhitespace(const char *buf, size_t n); -extern void FreeTokenized(std::vector *v); -extern void AppendSlice(std::vector *v, Slice *s); +extern std::vector ByteSliceFields(ByteSlice s); diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp index 528cc35e..cd4c9774 100644 --- a/windows/tools/lib_posix.cpp +++ b/windows/tools/lib_posix.cpp @@ -35,7 +35,7 @@ public: posixReadCloser(int fd); virtual ~posixReadCloser(void); - virtual Error *Read(void *buf, size_t n, size_t *actual); + virtual Error *Read(ByteSlice b, size_t *n); }; posixReadCloser::posixReadCloser(int fd) @@ -48,17 +48,17 @@ posixReadCloser::~posixReadCloser(void) close(this->fd); } -Error *posixReadCloser::Read(void *buf, size_t n, size_t *actual) +Error *posixReadCloser::Read(ByteSlice b, size_t *n) { ssize_t ret; - *actual = 0; - ret = read(this->fd, buf, n); + *n = 0; + ret = read(this->fd, b.Data(), b.Len()); if (ret < 0) return new posixError(errno); if (ret == 0) return NewEOF(); - *actual = ret; + *n = ret; return NULL; } @@ -68,7 +68,7 @@ public: posixWriteCloser(int fd); virtual ~posixWriteCloser(void); - virtual Error *Write(void *buf, size_t n); + virtual Error *Write(const ByteSlice b); }; posixWriteCloser::posixWriteCloser(int fd) @@ -81,14 +81,14 @@ posixWriteCloser::~posixWriteCloser(void) close(this->fd); } -Error *posixWriteCloser::Write(void *buf, size_t n) +Error *posixWriteCloser::Write(const ByteSlice &b) { ssize_t ret; - ret = write(this->fd, buf, n); + ret = write(this->fd, b.Data(), b.Len()); if (ret < 0) return new posixError(errno); - if (((size_t) ret) != n) + if (((size_t) ret) != b.Len()) return NewErrShortWrite(); return NULL; } From cf945367a36a7347f8913a3f6e0c60ce6782ab1f Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 16:32:33 -0400 Subject: [PATCH 17/30] Rewrote hresultwrap.cpp with the new changes, fixing some build errors too. Now to fix the remaining build errors. --- windows/tools/hresultwrap.cpp | 127 ++++++++++++++++------------------ windows/tools/lib.cpp | 8 ++- windows/tools/lib.hpp | 1 + 3 files changed, 69 insertions(+), 67 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 4fda9236..c6cfc303 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -4,97 +4,98 @@ #include #include "lib.hpp" -struct item { - Slice *name; - Slice *callingConvention; - Slice **params; - size_t nParams; - Slice *returns; +namespace { + +class items { +public: + ByteSlice name; + ByteSlice callingConvention; + std::vector params; + ByteSlice returns; bool keepReturn; - Slice *cond[2]; + ByteSlice cond[2]; }; -bool generate(const char *line, size_t n, FILE *fout) +#define noutbuf 2048 + +bool generate(ByteSlice line, FILE *fout) { - std::vector genout; - std::vector *tokens; + ByteSlice genout; + std::vector tokens; size_t i, j; - struct item item; + items item; size_t nw; - tokens = TokenizeWhitespace(line, n); + tokens = ByteSliceFields(line); - memset(&item, 0, sizeof (struct item)); + new (&item) items; i = 0; - item.returns = tokens->at(i); - if (item.returns->Data()[0] == '*') { - item.returns = new Slice(item.returns->Data() + 1, item.returns->Len() - 1); + item.returns = tokens.at(i); + item.keepReturn = false; + if (item.returns.Data()[0] == '*') { + item.returns = item.returns.Slice(1, item.returns.Len()); item.keepReturn = true; } i++; - if (tokens->size() % 2 == 1) { - item.callingConvention = tokens->at(i); + if (tokens.size() % 2 == 1) { + item.callingConvention = tokens.at(i); i++; } - item.name = tokens->at(i); + item.name = tokens.at(i); i++; - item.cond[0] = tokens->at(tokens->size() - 2); - item.cond[1] = tokens->at(tokens->size() - 1); - item.nParams = (tokens->size() - 2) - i; - item.params = new Slice *[item.nParams]; - for (j = 0; j < item.nParams; j++) { - item.params[j] = tokens->at(i); + item.cond[0] = tokens.at(tokens.size() - 2); + item.cond[1] = tokens.at(tokens.size() - 1); + item.params.reserve((tokens.size() - 2) - i); + for (j = 0; j < item.params.capacity(); j++) { + item.params.push_back(tokens.at(i)); i++; } - AppendString(&genout, "HRESULT "); - if (item.callingConvention != NULL) { - AppendSlice(&genout, item.callingConvention); - genout.push_back(' '); + genout = ByteSlice(0, noutbuf); + genout = genout.AppendString("HRESULT "); + if (item.callingConvention.Len() != 0) { + genout = genout.Append(item.callingConvention); + genout = genout.AppendString(" "); } - AppendSlice(&genout, item.name); - genout.push_back('('); - for (i = 0; i < item.nParams; i += 2) { - AppendSlice(&genout, item.params[i]); - genout.push_back(' '); - AppendSlice(&genout, item.params[i + 1]); - genout.push_back(','); - genout.push_back(' '); + genout = genout.Append(item.name); + genout = genout.AppendString("("); + for (i = 0; i < item.params.size(); i += 2) { + genout = genout.Append(item.params[i]); + genout = genout.AppendString(" "); + genout = genout.Append(item.params[i + 1]); + genout = genout.AppendString(", "); } if (item.keepReturn) { - AppendSlice(&genout, item.returns); - AppendString(&genout, " *ret"); - } else if (item.nParams != 0) { + genout = genout.Append(item.returns); + genout = genout.AppendString(" *ret"); + } else if (item.params.size() != 0) // remove the trailing comma and space - genout.pop_back(); - genout.pop_back(); - } else - AppendString(&genout, "void"); - genout.push_back(')'); - genout.push_back('\n'); + genout = genout.Slice(0, genout.Len() - 2); + else + genout = genout.AppendString("void"); + genout = genout.AppendString(")\n"); - delete[] item.params; - if (item.keepReturn) - delete item.returns; - FreeTokenized(tokens); + item.~items(); - genout.push_back('\n'); - nw = fwrite(genout.data(), sizeof (char), genout.size(), fout); - return nw == genout.size(); + genout = genout.AppendString("\n"); + nw = fwrite(genout.Data(), sizeof (char), genout.Len(), fout); + return nw == genout.Len(); } -bool process(const char *line, size_t n, FILE *fout) +bool process(ByteSlice line, FILE *fout) { size_t nw; - if (n > 0 && line[0] == '@') - return generate(line + 1, n - 1, fout); - nw = fwrite(line, sizeof (char), n, fout); - if (nw != n) + if (line.Len() > 0 && line.Data()[0] == '@') + return generate(line.Slice(1, line.Len()), fout); + nw = fwrite(line.Data(), sizeof (char), line.Len(), fout); + if (nw != line.Len()) return false; return fwrite("\n", sizeof (char), 1, fout) == 1; } +} + int main(int argc, char *argv[]) { ReadCloser *fin = NULL; @@ -120,17 +121,11 @@ int main(int argc, char *argv[]) } s = new Scanner(fin); - while (s->Scan()) { - const char *line; - size_t n; - - line = s->Bytes(); - n = s->Len(); - if (!process(line, n, fout)) { + while (s->Scan()) + if (!process(s->Bytes(), fout)) { fprintf(stderr, "error writing to %s\n", argv[2]); goto done; } - } if (s->Err() != 0) { fprintf(stderr, "error reading from %s: %s\n", argv[1], s->Err()->String()); goto done; diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index 36bf174d..310ab7b0 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -159,6 +159,12 @@ ByteSlice::ByteSlice(size_t len, size_t cap) this->cap = cap; } +ByteSlice::ByteSlice(int len, size_t cap) : + ByteSlice::ByteSlice((size_t) len, cap) +{ + // do nothing else +} + ByteSlice::~ByteSlice(void) { sliceRelease(this->data); @@ -305,7 +311,7 @@ bool Scanner::Scan(void) // otherwise, the buffer was exhausted in the middle of a line, so fall through } // need to refill the buffer - this->err = this->r->Read(this->buf, nbuf * sizeof (char), &n); + this->err = this->r->Read(this->buf, &n); if (this->err != NULL) return false; this->p = this->buf; diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index 2de42036..27405481 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -24,6 +24,7 @@ public: ByteSlice(ByteSlice &&b); // move constructor; sets b to ByteSlice() ByteSlice(const char *b, size_t n); ByteSlice(size_t len, size_t cap); + ByteSlice(int len, size_t cap); // deal with stupid rule about 0 ~ByteSlice(void); // note: copy assignment does not use copy-and-swap because I get neither copy-and-swap nor ADL public friend swap functions (https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom, https://stackoverflow.com/questions/5695548/public-friend-swap-member-function) From 620b03f4422eda312475f36ca529aedec716d4be Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 19:48:39 -0400 Subject: [PATCH 18/30] And fixed the remaining errors, including runtime erorrs. It works! --- windows/tools/hresultwrap.cpp | 3 --- windows/tools/lib.cpp | 23 +++++++++-------------- windows/tools/lib.hpp | 7 +++---- windows/tools/lib_posix.cpp | 2 +- 4 files changed, 13 insertions(+), 22 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index c6cfc303..ee73ad60 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -28,7 +28,6 @@ bool generate(ByteSlice line, FILE *fout) tokens = ByteSliceFields(line); - new (&item) items; i = 0; item.returns = tokens.at(i); item.keepReturn = false; @@ -75,8 +74,6 @@ bool generate(ByteSlice line, FILE *fout) genout = genout.AppendString("void"); genout = genout.AppendString(")\n"); - item.~items(); - genout = genout.AppendString("\n"); nw = fwrite(genout.Data(), sizeof (char), genout.Len(), fout); return nw == genout.Len(); diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp index 310ab7b0..da12dede 100644 --- a/windows/tools/lib.cpp +++ b/windows/tools/lib.cpp @@ -267,9 +267,8 @@ void ByteSlice::CopyFrom(const ByteSlice &b) Scanner::Scanner(ReadCloser *r) { this->r = r; - this->buf = new char[nbuf]; - this->p = this->buf; - this->n = 0; + this->buf = ByteSlice(nbuf, nbuf); + this->p = ByteSlice(); this->line = ByteSlice(0, nbuf); this->err = NULL; } @@ -278,7 +277,6 @@ Scanner::~Scanner(void) { if (this->err != NULL) delete this->err; - delete[] this->buf; } bool Scanner::Scan(void) @@ -289,23 +287,21 @@ bool Scanner::Scan(void) return false; this->line = this->line.Slice(0, 0); for (;;) { - if (this->n > 0) { + if (this->p.Len() > 0) { size_t j; bool haveline; haveline = false; - for (j = 0; j < this->n; j++) - if (this->p[j] == '\n') { + for (j = 0; j < this->p.Len(); j++) + if (this->p.Data()[j] == '\n') { haveline = true; break; } - this->line = this->line.Append(this->p, j); - this->p += j; - this->n -= j; + this->line = this->line.Append(this->p.Slice(0, j)); + this->p = this->p.Slice(j, this->p.Len()); if (haveline) { // swallow the \n for the next time through - this->p++; - this->n--; + this->p = this->p.Slice(1, this->p.Len()); return true; } // otherwise, the buffer was exhausted in the middle of a line, so fall through @@ -314,8 +310,7 @@ bool Scanner::Scan(void) this->err = this->r->Read(this->buf, &n); if (this->err != NULL) return false; - this->p = this->buf; - this->n = n; + this->p = this->buf.Slice(0, n); } } diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp index 27405481..417d6fbf 100644 --- a/windows/tools/lib.hpp +++ b/windows/tools/lib.hpp @@ -24,7 +24,7 @@ public: ByteSlice(ByteSlice &&b); // move constructor; sets b to ByteSlice() ByteSlice(const char *b, size_t n); ByteSlice(size_t len, size_t cap); - ByteSlice(int len, size_t cap); // deal with stupid rule about 0 + ByteSlice(int len, size_t cap); // deal with stupid rule about 0 (see https://stackoverflow.com/a/4610586/3408572) ~ByteSlice(void); // note: copy assignment does not use copy-and-swap because I get neither copy-and-swap nor ADL public friend swap functions (https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom, https://stackoverflow.com/questions/5695548/public-friend-swap-member-function) @@ -64,9 +64,8 @@ extern Error *CreateWrite(const char *filename, WriteCloser **w); class Scanner { ReadCloser *r; - char *buf; - const char *p; - size_t n; + ByteSlice buf; + ByteSlice p; ByteSlice line; Error *err; public: diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp index cd4c9774..1bd855cf 100644 --- a/windows/tools/lib_posix.cpp +++ b/windows/tools/lib_posix.cpp @@ -81,7 +81,7 @@ posixWriteCloser::~posixWriteCloser(void) close(this->fd); } -Error *posixWriteCloser::Write(const ByteSlice &b) +Error *posixWriteCloser::Write(const ByteSlice b) { ssize_t ret; From a1a20837cd258a3393d8adf2e5a0df0dec52b9bb Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 20:17:35 -0400 Subject: [PATCH 19/30] And cleaned up the item class, turning it into a Function class. --- windows/tools/hresultwrap.cpp | 127 ++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 51 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index ee73ad60..df1d3160 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -6,73 +6,98 @@ namespace { -class items { -public: +class Function { ByteSlice name; ByteSlice callingConvention; std::vector params; ByteSlice returns; bool keepReturn; ByteSlice cond[2]; +public: + Function(ByteSlice line); + + ByteSlice Signature(void) const; }; +Function::Function(ByteSlice line) +{ + std::vector fields; + size_t start; + + fields = ByteSliceFields(line); + + this->returns = fields[0]; + this->keepReturn = false; + if (this->returns.Data()[0] == '*') { + this->returns = this->returns.Slice(1, this->returns.Len()); + this->keepReturn = true; + } + + start = 2; + this->name = fields[1]; + if (fields.size() % 2 == 1) { + start = 3; + this->callingConvention = fields[1]; + this->name = fields[2]; + } + + this->cond[1] = fields.back(); + fields.pop_back(); + this->cond[0] = fields.back(); + fields.pop_back(); + + this->params = std::vector(fields.begin() + start, fields.end()); +} + +#define nfuncoutbuf 256 + +ByteSlice Function::Signature(void) const +{ + ByteSlice out; + size_t i; + + out = ByteSlice(0, nfuncoutbuf); + + out = out.AppendString(u8"HRESULT "); + if (this->callingConvention.Len() != 0) { + out = out.Append(this->callingConvention); + out = out.AppendString(u8" "); + } + out = out.Append(this->name); + + out = out.AppendString(u8"("); + for (i = 0; i < this->params.size(); i += 2) { + out = out.Append(this->params[i]); + out = out.AppendString(u8" "); + out = out.Append(this->params[i + 1]); + out = out.AppendString(u8", "); + } + if (this->keepReturn) { + out = out.Append(this->returns); + out = out.AppendString(u8" *ret"); + } else if (this->params.size() != 0) + // remove the trailing comma and space + out = out.Slice(0, out.Len() - 2); + else + out = out.AppendString(u8"void"); + + out = out.AppendString(u8")\n"); + return out; +} + #define noutbuf 2048 bool generate(ByteSlice line, FILE *fout) { ByteSlice genout; - std::vector tokens; - size_t i, j; - items item; + Function *f; size_t nw; - tokens = ByteSliceFields(line); - - i = 0; - item.returns = tokens.at(i); - item.keepReturn = false; - if (item.returns.Data()[0] == '*') { - item.returns = item.returns.Slice(1, item.returns.Len()); - item.keepReturn = true; - } - i++; - if (tokens.size() % 2 == 1) { - item.callingConvention = tokens.at(i); - i++; - } - item.name = tokens.at(i); - i++; - item.cond[0] = tokens.at(tokens.size() - 2); - item.cond[1] = tokens.at(tokens.size() - 1); - item.params.reserve((tokens.size() - 2) - i); - for (j = 0; j < item.params.capacity(); j++) { - item.params.push_back(tokens.at(i)); - i++; - } - genout = ByteSlice(0, noutbuf); - genout = genout.AppendString("HRESULT "); - if (item.callingConvention.Len() != 0) { - genout = genout.Append(item.callingConvention); - genout = genout.AppendString(" "); - } - genout = genout.Append(item.name); - genout = genout.AppendString("("); - for (i = 0; i < item.params.size(); i += 2) { - genout = genout.Append(item.params[i]); - genout = genout.AppendString(" "); - genout = genout.Append(item.params[i + 1]); - genout = genout.AppendString(", "); - } - if (item.keepReturn) { - genout = genout.Append(item.returns); - genout = genout.AppendString(" *ret"); - } else if (item.params.size() != 0) - // remove the trailing comma and space - genout = genout.Slice(0, genout.Len() - 2); - else - genout = genout.AppendString("void"); - genout = genout.AppendString(")\n"); + + f = new Function(line); + genout = genout.Append(f->Signature()); + delete f; genout = genout.AppendString("\n"); nw = fwrite(genout.Data(), sizeof (char), genout.Len(), fout); From eef179c1e50d58f38826a79f2f8ebdd919dae98e Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 20:38:10 -0400 Subject: [PATCH 20/30] And added function bodies to hresultwrap. --- windows/tools/hresultwrap.cpp | 74 ++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index df1d3160..cd3f45f2 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -17,6 +17,8 @@ public: Function(ByteSlice line); ByteSlice Signature(void) const; + ByteSlice Call(void) const; + ByteSlice Body(void) const; }; Function::Function(ByteSlice line) @@ -80,8 +82,75 @@ ByteSlice Function::Signature(void) const out = out.Slice(0, out.Len() - 2); else out = out.AppendString(u8"void"); + out = out.AppendString(u8")"); + return out; +} + +ByteSlice Function::Call(void) const +{ + ByteSlice out; + size_t i; + + out = ByteSlice(0, nfuncoutbuf); + out = out.Append(this->name); + out = out.AppendString(u8"("); + for (i = 0; i < this->params.size(); i += 2) { + out = out.Append(this->params[i + 1]); + out = out.AppendString(u8", "); + } + if (this->params.size() != 0) + // remove the trailing comma and space + out = out.Slice(0, out.Len() - 2); + out = out.AppendString(u8")"); + return out; +} + +#define nbodybuf 1024 + +ByteSlice Function::Body(void) const +{ + ByteSlice out; + + out = ByteSlice(0, nbodybuf); + out = out.AppendString(u8"{\n"); + + if (!this->keepReturn) { + out = out.AppendString(u8"\t"); + out = out.Append(this->returns); + out = out.AppendString(u8" ret;\n"); + } + out = out.AppendString(u8"\tDWORD lasterr;\n"); + out = out.AppendString(u8"\n"); + + if (this->keepReturn) { + out = out.AppendString(u8"\tif (ret == NULL)\n"); + out = out.AppendString(u8"\t\treturn E_POINTER;\n"); + } + + out = out.AppendString(u8"\tSetLastError(0);\n"); + out = out.AppendString(u8"\t"); + if (this->keepReturn) + out = out.AppendString(u8"*"); + out = out.AppendString(u8"ret = "); + out = out.Append(this->Call()); + out = out.AppendString(u8";\n"); + out = out.AppendString(u8"\tlasterr = GetLastError();\n"); + + out = out.AppendString(u8"\tif ("); + if (this->keepReturn) + out = out.AppendString(u8"*"); + out = out.AppendString(u8"ret "); + out = out.Append(this->cond[0]); + out = out.AppendString(u8" "); + out = out.Append(this->cond[1]); out = out.AppendString(u8")\n"); + out = out.AppendString(u8"\t\treturn lastErrorToHRESULT(lasterr, \""); + out = out.Append(this->name); + out = out.AppendString(u8"()\");\n"); + out = out.AppendString(u8"\treturn S_OK;\n"); + + out = out.AppendString(u8"}"); return out; } @@ -97,9 +166,12 @@ bool generate(ByteSlice line, FILE *fout) f = new Function(line); genout = genout.Append(f->Signature()); + genout = genout.AppendString(u8"\n"); + genout = genout.Append(f->Body()); delete f; - genout = genout.AppendString("\n"); + genout = genout.AppendString(u8"\n"); + genout = genout.AppendString(u8"\n"); nw = fwrite(genout.Data(), sizeof (char), genout.Len(), fout); return nw == genout.Len(); } From ea5bd79b89f2639274d6bf2a68b6c856ed0bf3b9 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sun, 27 May 2018 20:44:34 -0400 Subject: [PATCH 21/30] Made WINAPI (stdcall) the default calling convention. Hopefully this will opt us into some compiler optimizations... hopefully. --- windows/tools/hresultwrap.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index cd3f45f2..7de09948 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -36,6 +36,7 @@ Function::Function(ByteSlice line) } start = 2; + this->callingConvention = ByteSlice().AppendString(u8"WINAPI"); this->name = fields[1]; if (fields.size() % 2 == 1) { start = 3; @@ -61,10 +62,8 @@ ByteSlice Function::Signature(void) const out = ByteSlice(0, nfuncoutbuf); out = out.AppendString(u8"HRESULT "); - if (this->callingConvention.Len() != 0) { - out = out.Append(this->callingConvention); - out = out.AppendString(u8" "); - } + out = out.Append(this->callingConvention); + out = out.AppendString(u8" "); out = out.Append(this->name); out = out.AppendString(u8"("); From b590482ccba533dd959752bc32407e2b945e67f4 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Mon, 28 May 2018 22:46:30 -0400 Subject: [PATCH 22/30] Expanded the tool input slightly and (finally) changed hresultwrap.cpp to use WriteCloser. --- windows/tools/a | 11 +++++++++++ windows/tools/hresultwrap.cpp | 36 +++++++++++++++++------------------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/windows/tools/a b/windows/tools/a index fd4ff220..1c0007fe 100644 --- a/windows/tools/a +++ b/windows/tools/a @@ -1,3 +1,14 @@ +static HRESULT lastErrorToHRESULT(DWORD lasterr, const char *funcname) +{ + HRESULT hr; + + hr = E_FAIL; + if (lasterr != 0) + hr = HRESULT_FROM_WIN32(lasterr); + uiprivImplBug("error calling %s: last error %I32d\n", funcname, lasterr); + return hr; +} + @BOOL UnregisterClassW LPCWSTR className HINSTANCE hInstance == 0 @*HWND CreateWindowExW DWORD exstyle LPCWSTR className LPCWSTR title DWORD style int x int y int width int height HWND parent HMENU menu HINSTANCE hInstance LPVOID lpParam == NULL @BOOL DestroyWindow HWND hwnd == 0 diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index 7de09948..a94afd62 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -155,11 +155,10 @@ ByteSlice Function::Body(void) const #define noutbuf 2048 -bool generate(ByteSlice line, FILE *fout) +Error *generate(ByteSlice line, WriteCloser *fout) { ByteSlice genout; Function *f; - size_t nw; genout = ByteSlice(0, noutbuf); @@ -171,20 +170,19 @@ bool generate(ByteSlice line, FILE *fout) genout = genout.AppendString(u8"\n"); genout = genout.AppendString(u8"\n"); - nw = fwrite(genout.Data(), sizeof (char), genout.Len(), fout); - return nw == genout.Len(); + return fout->Write(genout); } -bool process(ByteSlice line, FILE *fout) +Error *process(ByteSlice line, WriteCloser *fout) { - size_t nw; + Error *err; if (line.Len() > 0 && line.Data()[0] == '@') return generate(line.Slice(1, line.Len()), fout); - nw = fwrite(line.Data(), sizeof (char), line.Len(), fout); - if (nw != line.Len()) - return false; - return fwrite("\n", sizeof (char), 1, fout) == 1; + err = fout->Write(line); + if (err != NULL) + return err; + return fout->Write(ByteSlice().AppendString("\n")); } } @@ -192,7 +190,7 @@ bool process(ByteSlice line, FILE *fout) int main(int argc, char *argv[]) { ReadCloser *fin = NULL; - FILE *fout = NULL; + WriteCloser *fout = NULL; Scanner *s = NULL; int ret = 1; Error *err = NULL; @@ -207,18 +205,20 @@ int main(int argc, char *argv[]) fprintf(stderr, "error opening %s: %s\n", argv[1], err->String()); goto done; } - fout = fopen(argv[2], "wb"); - if (fout == NULL) { - fprintf(stderr, "error creating %s\n", argv[2]); + err = CreateWrite(argv[2], &fout); + if (err != NULL) { + fprintf(stderr, "error creating %s: %s\n", argv[2], err->String()); goto done; } s = new Scanner(fin); - while (s->Scan()) - if (!process(s->Bytes(), fout)) { - fprintf(stderr, "error writing to %s\n", argv[2]); + while (s->Scan()) { + err = process(s->Bytes(), fout); + if (err != NULL) { + fprintf(stderr, "error processing line: %s\n", argv[2], err->String()); goto done; } + } if (s->Err() != 0) { fprintf(stderr, "error reading from %s: %s\n", argv[1], s->Err()->String()); goto done; @@ -229,7 +229,7 @@ done: if (s != NULL) delete s; if (fout != NULL) - fclose(fout); + delete fout; if (fin != NULL) delete fin; if (err != NULL) From d4517fab84adc2f80301167e4a9e247e215d2426 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Mon, 28 May 2018 22:50:00 -0400 Subject: [PATCH 23/30] And changed hresultwrap to only write to the output file in main(). --- windows/tools/hresultwrap.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index a94afd62..d91fca70 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -155,7 +155,7 @@ ByteSlice Function::Body(void) const #define noutbuf 2048 -Error *generate(ByteSlice line, WriteCloser *fout) +ByteSlice generate(ByteSlice line) { ByteSlice genout; Function *f; @@ -170,19 +170,14 @@ Error *generate(ByteSlice line, WriteCloser *fout) genout = genout.AppendString(u8"\n"); genout = genout.AppendString(u8"\n"); - return fout->Write(genout); + return genout; } -Error *process(ByteSlice line, WriteCloser *fout) +ByteSlice process(ByteSlice line) { - Error *err; - if (line.Len() > 0 && line.Data()[0] == '@') - return generate(line.Slice(1, line.Len()), fout); - err = fout->Write(line); - if (err != NULL) - return err; - return fout->Write(ByteSlice().AppendString("\n")); + return generate(line.Slice(1, line.Len())); + return line.AppendString("\n"); } } @@ -192,6 +187,7 @@ int main(int argc, char *argv[]) ReadCloser *fin = NULL; WriteCloser *fout = NULL; Scanner *s = NULL; + ByteSlice b; int ret = 1; Error *err = NULL; @@ -213,14 +209,17 @@ int main(int argc, char *argv[]) s = new Scanner(fin); while (s->Scan()) { - err = process(s->Bytes(), fout); + b = process(s->Bytes()); + err = fout->Write(b); if (err != NULL) { - fprintf(stderr, "error processing line: %s\n", argv[2], err->String()); + fprintf(stderr, "error writing to %s: %s\n", argv[2], err->String()); goto done; } } - if (s->Err() != 0) { - fprintf(stderr, "error reading from %s: %s\n", argv[1], s->Err()->String()); + err = s->Err(); + if (err != NULL) { + fprintf(stderr, "error reading from %s: %s\n", argv[1], err->String()); + err = NULL; // we don't own err here goto done; } From 039a9db2e5d3ddebfe39b5699a3dd5659f33e185 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Mon, 28 May 2018 22:57:52 -0400 Subject: [PATCH 24/30] Wrapped the processing in a class and collapsed consecutive blank lines. --- windows/tools/hresultwrap.cpp | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp index d91fca70..82450204 100644 --- a/windows/tools/hresultwrap.cpp +++ b/windows/tools/hresultwrap.cpp @@ -153,14 +153,31 @@ ByteSlice Function::Body(void) const return out; } +class Processor { + bool previousLineBlank; + + ByteSlice generate(ByteSlice line); +public: + Processor(void); + + ByteSlice Process(ByteSlice line); +}; + +Processor::Processor(void) +{ + this->previousLineBlank = false; +} + #define noutbuf 2048 -ByteSlice generate(ByteSlice line) +ByteSlice Processor::generate(ByteSlice line) { ByteSlice genout; Function *f; genout = ByteSlice(0, noutbuf); + if (!this->previousLineBlank) + genout = genout.AppendString("\n"); f = new Function(line); genout = genout.Append(f->Signature()); @@ -169,14 +186,20 @@ ByteSlice generate(ByteSlice line) delete f; genout = genout.AppendString(u8"\n"); - genout = genout.AppendString(u8"\n"); + this->previousLineBlank = false; return genout; } -ByteSlice process(ByteSlice line) +ByteSlice Processor::Process(ByteSlice line) { if (line.Len() > 0 && line.Data()[0] == '@') - return generate(line.Slice(1, line.Len())); + return this->generate(line.Slice(1, line.Len())); + if (line.Len() == 0) { + if (this->previousLineBlank) + return ByteSlice(); + this->previousLineBlank = true; + } else + this->previousLineBlank = false; return line.AppendString("\n"); } @@ -187,6 +210,7 @@ int main(int argc, char *argv[]) ReadCloser *fin = NULL; WriteCloser *fout = NULL; Scanner *s = NULL; + Processor p; ByteSlice b; int ret = 1; Error *err = NULL; @@ -209,7 +233,7 @@ int main(int argc, char *argv[]) s = new Scanner(fin); while (s->Scan()) { - b = process(s->Bytes()); + b = p.Process(s->Bytes()); err = fout->Write(b); if (err != NULL) { fprintf(stderr, "error writing to %s: %s\n", argv[2], err->String()); From c33ea32e0fd61f6a7b25393004ffface4d14e148 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 8 Aug 2018 19:48:52 -0400 Subject: [PATCH 25/30] Started a new hresultwrap in Go. I'll run it locally. --- windows/tools/funclist.textpb | 18 ++++++++++++++++++ windows/tools/hresultwrap.go | 30 ++++++++++++++++++++++++++++++ windows/tools/hresultwrap.proto | 18 ++++++++++++++++++ windows/tools/mk.sh | 3 +++ 4 files changed, 69 insertions(+) create mode 100644 windows/tools/funclist.textpb create mode 100644 windows/tools/hresultwrap.go create mode 100644 windows/tools/hresultwrap.proto create mode 100644 windows/tools/mk.sh diff --git a/windows/tools/funclist.textpb b/windows/tools/funclist.textpb new file mode 100644 index 00000000..62b105fc --- /dev/null +++ b/windows/tools/funclist.textpb @@ -0,0 +1,18 @@ +# 8 august 2018 + +func: { +name: "RegisterClassW" +arg: "_In_ CONST WNDCLASSW *lpWndClass" +ret: "ATOM" +failval: "0" +save: true +} + +func: { +name: "UnregisterClassW" +arg: "_In_ LPCWSTR lpClassName" +arg: "_In_opt_ HINSTANCE hInstance" +ret: "BOOL" +failval: "0" +cleanup: true +} diff --git a/windows/tools/hresultwrap.go b/windows/tools/hresultwrap.go new file mode 100644 index 00000000..b806cd9f --- /dev/null +++ b/windows/tools/hresultwrap.go @@ -0,0 +1,30 @@ +// 8 august 2018 +// usage: hresultwrap funclist template out +package main + +import ( + "fmt" + "os" + "io/ioutil" + + "github.com/golang/protobuf/proto" +) + +func main() { + if len(os.Args) != 2 { + fmt.Fprintf(os.Stderr, "usage: %s funclist\n", os.Args[0]) + os.Exit(1) + } + b, err := ioutil.ReadFile(os.Args[1]) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading %s: %v\n", os.Args[1], err) + os.Exit(1) + } + var f File + err = proto.UnmarshalText(string(b), &f) + if err != nil { + fmt.Fprintf(os.Stderr, "error parsing %s: %v\n", os.Args[1], err) + os.Exit(1) + } + fmt.Println(f) +} diff --git a/windows/tools/hresultwrap.proto b/windows/tools/hresultwrap.proto new file mode 100644 index 00000000..07801212 --- /dev/null +++ b/windows/tools/hresultwrap.proto @@ -0,0 +1,18 @@ +// 8 august 2018 +syntax = "proto3"; + +option go_package = "main"; + +message File { + repeated Function func = 1; +} + +message Function { + string name = 1; + string calling_convention = 2; // defaults to WINAPI + repeated string arg = 3; + string ret = 4; + string failval = 5; + bool save = 6; + bool cleanup = 7; +} diff --git a/windows/tools/mk.sh b/windows/tools/mk.sh new file mode 100644 index 00000000..5a2c95cd --- /dev/null +++ b/windows/tools/mk.sh @@ -0,0 +1,3 @@ +rm -f hresultwrap.pb.go hresultwrap +protoc --go_out=. hresultwrap.proto +go build hresultwrap.go hresultwrap.pb.go From 1f4d7dc3748d86812cc705cc60d9316d413db40a Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 8 Aug 2018 19:51:20 -0400 Subject: [PATCH 26/30] Adjusted mk.sh slightly. --- windows/tools/mk.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) mode change 100644 => 100755 windows/tools/mk.sh diff --git a/windows/tools/mk.sh b/windows/tools/mk.sh old mode 100644 new mode 100755 index 5a2c95cd..304d48f7 --- a/windows/tools/mk.sh +++ b/windows/tools/mk.sh @@ -1,3 +1,4 @@ -rm -f hresultwrap.pb.go hresultwrap -protoc --go_out=. hresultwrap.proto -go build hresultwrap.go hresultwrap.pb.go +rm -f hresultwrap.pb.go hresultwrap && +protoc --go_out=. hresultwrap.proto && +go build hresultwrap.go hresultwrap.pb.go && +./hresultwrap funclist.textpb From ecf9efd6d7cc1b60e7283106833e5960e07e4020 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 8 Aug 2018 20:53:32 -0400 Subject: [PATCH 27/30] More functions in funclist.proto. --- windows/tools/a | 15 ----- windows/tools/funclist.textpb | 116 ++++++++++++++++++++++++++++++++++ windows/tools/gen.sh | 1 + windows/tools/mk.sh | 3 +- 4 files changed, 118 insertions(+), 17 deletions(-) create mode 100755 windows/tools/gen.sh diff --git a/windows/tools/a b/windows/tools/a index 1c0007fe..7f6648df 100644 --- a/windows/tools/a +++ b/windows/tools/a @@ -9,21 +9,6 @@ static HRESULT lastErrorToHRESULT(DWORD lasterr, const char *funcname) return hr; } -@BOOL UnregisterClassW LPCWSTR className HINSTANCE hInstance == 0 -@*HWND CreateWindowExW DWORD exstyle LPCWSTR className LPCWSTR title DWORD style int x int y int width int height HWND parent HMENU menu HINSTANCE hInstance LPVOID lpParam == NULL -@BOOL DestroyWindow HWND hwnd == 0 -@BOOL UpdateWindow HWND hwnd == 0 -@BOOL AdustWindowRectEx LPRECT r DWORD style BOOL hasMenu DWORD exStyle == 0 - -@*BOOL GetMessageW LPMSG msg HWND hwnd UINT minMsg UINT maxMsg < 0 -@BOOL PostMessageW HWND hwnd UINT uMsg WPARAM wParam LPARAM lParam == 0 -@UINT_PTR SetTimer HWND hwnd UINT_PTR id UINT time TIMERPROC proc == 0 -@BOOL KillTimer HWND hwnd UINT_PTR id == 0 - -@int GetWindowTextW HWND hwnd LPWSTR str int n == 0 -@BOOL SetWindowTextW HWND hwnd LPCWSTR str == 0 -@BOOL SetWindowPos HWND hwnd HWND insertAfter int x int y int cx int cy UINT flags == 0 -$typedef WINDOWPLACEMENT *uiprivLPWINDOWPLACEMENT; @BOOL GetWindowPlacement HWND hwnd uiprivLPWWINDOWPLACEMENT wp == 0 $typedef const WINDOWPLACEMENT *uiprivLPCWINDOWPLACEMENT; @BOOL SetWindowPlacement HWND hwnd uiprivLPCWINDOWPLACEMENT wp == 0 diff --git a/windows/tools/funclist.textpb b/windows/tools/funclist.textpb index 62b105fc..c876732a 100644 --- a/windows/tools/funclist.textpb +++ b/windows/tools/funclist.textpb @@ -1,5 +1,83 @@ # 8 august 2018 +# TODO preserve lpRect on failure +func: { +name: "AdjustWindowRectEx" +arg: "_Inout_ LPRECT lpRect" +arg: "_In_ DWORD dwStyle" +arg: "_In_ BOOL bMenu" +arg: "_In_ DWORD dwExStyle" +ret: "BOOL" +failval: "0" +} + +func: { +name: "CreateWindowExW" +arg: "_In_ DWORD dwExStyle" +arg: "_In_opt_ LPCWSTR lpClassName" +arg: "_In_opt_ LPCWSTR lpWindowName" +arg: "_In_ DWORD dwStyle" +arg: "_In_ int X" +arg: "_In_ int Y" +arg: "_In_ int nWidth" +arg: "_In_ int nHeight" +arg: "_In_opt_ HWND hWndParent" +arg: "_In_opt_ HMENU hMenu" +arg: "_In_opt_ HINSTANCE hInstance" +arg: "_In_opt_ LPVOID lpParam" +ret: "HWND" +failval: "NULL" +save: true +} + +func: { +name: "DestroyWindow" +arg: "_In_ HWND hWnd" +ret: "BOOL" +failval: "0" +cleanup: true +} + +# TODO failexpr is < 0 +func: { +name: "GetMessageW" +arg: "_Out_ LPMSG lpMsg" +arg: "_In_opt_ HWND hWnd" +arg: "_In_ UINT wMsgFilterMin" +arg: "_In_ UINT wMsgFilterMax" +ret: "BOOL" +failval: "-1" +} + +# TODO write a L'\0' to lpString[0] on failure +# TODO also add extra checks to make sure lpString is not NULL +func: { +name: "GetWindowTextW" +arg: "_In_ HWND hWnd" +arg: "_Out_writes_(nMaxCount) LPWSTR lpString" +arg: "_In_ int nMaxCount" +ret: "int" +failval: "0" +} + +func: { +name: "KillTimer" +arg: "_In_opt_ HWND hWnd" +arg: "_In_ UINT_PTR uIDEvent" +ret: "BOOL" +failval: "0" +} + +func: { +name: "PostMessageW" +arg: "_In_opt_ HWND hWnd" +arg: "_In_ UINT Msg" +arg: "_In_ WPARAM wParam" +arg: "_In_ LPARAM lParam" +ret: "BOOL" +failval: "0" +} + func: { name: "RegisterClassW" arg: "_In_ CONST WNDCLASSW *lpWndClass" @@ -8,6 +86,37 @@ failval: "0" save: true } +func: { +name: "SetTimer" +arg: "_In_opt_ HWND hWnd" +arg: "_In_ UINT_PTR nIDEvent" +arg: "_In_ UINT uElapse" +arg: "_In_opt_ TIMERPROC lpTimerFunc" +ret: "UINT_PTR" +failval: "0" +} + +func: { +name: "SetWindowPos" +arg: "_In_ HWND hWnd" +arg: "_In_opt_ HWND hWndInsertAfter" +arg: "_In_ int X" +arg: "_In_ int Y" +arg: "_In_ int cx" +arg: "_In_ int cy" +arg: "_In_ UINT uFlags" +ret: "BOOL" +failval: "0" +} + +func: { +name: "SetWindowTextW" +arg: "_In_ HWND hWnd" +arg: "_In_opt_ LPCWSTR lpString" +ret: "BOOL" +failval: "0" +} + func: { name: "UnregisterClassW" arg: "_In_ LPCWSTR lpClassName" @@ -16,3 +125,10 @@ ret: "BOOL" failval: "0" cleanup: true } + +func: { +name: "UpdateWindow" +arg: "_In_ HWND hWnd" +ret: "BOOL" +failval: "0" +} diff --git a/windows/tools/gen.sh b/windows/tools/gen.sh new file mode 100755 index 00000000..7f39837f --- /dev/null +++ b/windows/tools/gen.sh @@ -0,0 +1 @@ +./hresultwrap funclist.textpb diff --git a/windows/tools/mk.sh b/windows/tools/mk.sh index 304d48f7..276c3aae 100755 --- a/windows/tools/mk.sh +++ b/windows/tools/mk.sh @@ -1,4 +1,3 @@ rm -f hresultwrap.pb.go hresultwrap && protoc --go_out=. hresultwrap.proto && -go build hresultwrap.go hresultwrap.pb.go && -./hresultwrap funclist.textpb +go build hresultwrap.go hresultwrap.pb.go From b3de605d50bfcbeedd6df70931594522f9738fdc Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 8 Aug 2018 21:31:12 -0400 Subject: [PATCH 28/30] Started template support, writing the initial C++ template. --- windows/tools/a | 11 --------- windows/tools/cpp.template | 29 +++++++++++++++++++++++ windows/tools/gen.sh | 2 +- windows/tools/hresultwrap.go | 46 +++++++++++++++++++++++++++++++++--- 4 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 windows/tools/cpp.template diff --git a/windows/tools/a b/windows/tools/a index 7f6648df..5be22d75 100644 --- a/windows/tools/a +++ b/windows/tools/a @@ -1,14 +1,3 @@ -static HRESULT lastErrorToHRESULT(DWORD lasterr, const char *funcname) -{ - HRESULT hr; - - hr = E_FAIL; - if (lasterr != 0) - hr = HRESULT_FROM_WIN32(lasterr); - uiprivImplBug("error calling %s: last error %I32d\n", funcname, lasterr); - return hr; -} - @BOOL GetWindowPlacement HWND hwnd uiprivLPWWINDOWPLACEMENT wp == 0 $typedef const WINDOWPLACEMENT *uiprivLPCWINDOWPLACEMENT; @BOOL SetWindowPlacement HWND hwnd uiprivLPCWINDOWPLACEMENT wp == 0 diff --git a/windows/tools/cpp.template b/windows/tools/cpp.template new file mode 100644 index 00000000..ced37e58 --- /dev/null +++ b/windows/tools/cpp.template @@ -0,0 +1,29 @@ +{{/* 8 august 2018 */}}// this file is generated by tools/hresultwrap and should NOT be modified directly +#include "uipriv_windows.hpp" + +static inline HRESULT lastErrorToHRESULT(DWORD lasterr, const char *funcname) +{ + HRESULT hr; + + hr = E_FAIL; + if (lasterr != 0) + hr = HRESULT_FROM_WIN32(lasterr); + uiprivImplBug("error calling %s: last error %I32d\n", funcname, lasterr); + return hr; +}{{range .}} + +{{$narg := len .Arg}}HRESULT {{if .CallingConvention}}{{.CallingConvention}}{{else}}WINAPI{{end}} uiprivHR{{.Name}}({{range $i, $a := .Arg}}{{$a}}{{argcomma $i $narg}}{{end}}{{if .Save}}, _Out_ {{.Ret}} *outRet{{end}}) +{ + {{.Ret}} xyzret; + DWORD xyzlasterr; + +{{if .Save}} if (outRet == NULL) + return E_POINTER; +{{end}} SetLastError(0); + xyzret = {{.Name}}({{range $i, $a := .Arg}}{{argname $a}}{{argcomma $i $narg}}{{end}}); + xyzlasterr = GetLastError(); +{{if .Save}} *outRet = xyzret; +{{end}} if (xyzret != {{.Failval}}) + return S_OK; + return lastErrToHRESULT(xyzlasterr, "{{.Name}}()"); +}{{end}} diff --git a/windows/tools/gen.sh b/windows/tools/gen.sh index 7f39837f..168df8fa 100755 --- a/windows/tools/gen.sh +++ b/windows/tools/gen.sh @@ -1 +1 @@ -./hresultwrap funclist.textpb +./hresultwrap funclist.textpb cpp.template diff --git a/windows/tools/hresultwrap.go b/windows/tools/hresultwrap.go index b806cd9f..edf9e6b2 100644 --- a/windows/tools/hresultwrap.go +++ b/windows/tools/hresultwrap.go @@ -6,13 +6,43 @@ import ( "fmt" "os" "io/ioutil" + "text/template" + "strings" "github.com/golang/protobuf/proto" ) +func argname(arg string) string { + fields := strings.Fields(arg) + last := fields[len(fields) - 1] + start := strings.LastIndexFunc(last, func(r rune) bool { + return !(r >= 'A' && r <= 'Z') && + !(r >= 'a' && r <= 'z') && + !(r >= '0' && r <= '9') && + r != '_' + }) + if start == -1 { + return last + } + // TODO replace + 1 with + len of that last rune + return last[start + 1:] +} + +func argcomma(n, len int) string { + if n == len - 1 { + return "" + } + return ", " +} + +var templateFuncs = template.FuncMap{ + "argname": argname, + "argcomma": argcomma, +} + func main() { - if len(os.Args) != 2 { - fmt.Fprintf(os.Stderr, "usage: %s funclist\n", os.Args[0]) + if len(os.Args) != 3 { + fmt.Fprintf(os.Stderr, "usage: %s funclist template\n", os.Args[0]) os.Exit(1) } b, err := ioutil.ReadFile(os.Args[1]) @@ -26,5 +56,15 @@ func main() { fmt.Fprintf(os.Stderr, "error parsing %s: %v\n", os.Args[1], err) os.Exit(1) } - fmt.Println(f) + + tmpl, err := template.New(os.Args[2]).Funcs(templateFuncs).ParseFiles(os.Args[2]) + if err != nil { + fmt.Fprintf(os.Stderr, "error parsing %s: %v\n", os.Args[2], err) + os.Exit(1) + } + err = tmpl.Execute(os.Stdout, f.Func) + if err != nil { + fmt.Fprintf(os.Stderr, "error executing template: %v\n", err) + os.Exit(1) + } } From ea1fde52ad812b90f4cbd09150a50ebbbb43ba95 Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Wed, 8 Aug 2018 21:31:58 -0400 Subject: [PATCH 29/30] More TODOs and removed the old C++. --- windows/tools/cpp.template | 2 +- windows/tools/hresultwrap.cpp | 261 ------------------------- windows/tools/lib.cpp | 349 ---------------------------------- windows/tools/lib.hpp | 80 -------- windows/tools/lib_posix.cpp | 118 ------------ 5 files changed, 1 insertion(+), 809 deletions(-) delete mode 100644 windows/tools/hresultwrap.cpp delete mode 100644 windows/tools/lib.cpp delete mode 100644 windows/tools/lib.hpp delete mode 100644 windows/tools/lib_posix.cpp diff --git a/windows/tools/cpp.template b/windows/tools/cpp.template index ced37e58..a9627093 100644 --- a/windows/tools/cpp.template +++ b/windows/tools/cpp.template @@ -26,4 +26,4 @@ static inline HRESULT lastErrorToHRESULT(DWORD lasterr, const char *funcname) {{end}} if (xyzret != {{.Failval}}) return S_OK; return lastErrToHRESULT(xyzlasterr, "{{.Name}}()"); -}{{end}} +}{{/*TODO cleanup*/}}{{end}} diff --git a/windows/tools/hresultwrap.cpp b/windows/tools/hresultwrap.cpp deleted file mode 100644 index 82450204..00000000 --- a/windows/tools/hresultwrap.cpp +++ /dev/null @@ -1,261 +0,0 @@ -// 21 may 2018 -#include -#include -#include -#include "lib.hpp" - -namespace { - -class Function { - ByteSlice name; - ByteSlice callingConvention; - std::vector params; - ByteSlice returns; - bool keepReturn; - ByteSlice cond[2]; -public: - Function(ByteSlice line); - - ByteSlice Signature(void) const; - ByteSlice Call(void) const; - ByteSlice Body(void) const; -}; - -Function::Function(ByteSlice line) -{ - std::vector fields; - size_t start; - - fields = ByteSliceFields(line); - - this->returns = fields[0]; - this->keepReturn = false; - if (this->returns.Data()[0] == '*') { - this->returns = this->returns.Slice(1, this->returns.Len()); - this->keepReturn = true; - } - - start = 2; - this->callingConvention = ByteSlice().AppendString(u8"WINAPI"); - this->name = fields[1]; - if (fields.size() % 2 == 1) { - start = 3; - this->callingConvention = fields[1]; - this->name = fields[2]; - } - - this->cond[1] = fields.back(); - fields.pop_back(); - this->cond[0] = fields.back(); - fields.pop_back(); - - this->params = std::vector(fields.begin() + start, fields.end()); -} - -#define nfuncoutbuf 256 - -ByteSlice Function::Signature(void) const -{ - ByteSlice out; - size_t i; - - out = ByteSlice(0, nfuncoutbuf); - - out = out.AppendString(u8"HRESULT "); - out = out.Append(this->callingConvention); - out = out.AppendString(u8" "); - out = out.Append(this->name); - - out = out.AppendString(u8"("); - for (i = 0; i < this->params.size(); i += 2) { - out = out.Append(this->params[i]); - out = out.AppendString(u8" "); - out = out.Append(this->params[i + 1]); - out = out.AppendString(u8", "); - } - if (this->keepReturn) { - out = out.Append(this->returns); - out = out.AppendString(u8" *ret"); - } else if (this->params.size() != 0) - // remove the trailing comma and space - out = out.Slice(0, out.Len() - 2); - else - out = out.AppendString(u8"void"); - out = out.AppendString(u8")"); - - return out; -} - -ByteSlice Function::Call(void) const -{ - ByteSlice out; - size_t i; - - out = ByteSlice(0, nfuncoutbuf); - out = out.Append(this->name); - out = out.AppendString(u8"("); - for (i = 0; i < this->params.size(); i += 2) { - out = out.Append(this->params[i + 1]); - out = out.AppendString(u8", "); - } - if (this->params.size() != 0) - // remove the trailing comma and space - out = out.Slice(0, out.Len() - 2); - out = out.AppendString(u8")"); - return out; -} - -#define nbodybuf 1024 - -ByteSlice Function::Body(void) const -{ - ByteSlice out; - - out = ByteSlice(0, nbodybuf); - out = out.AppendString(u8"{\n"); - - if (!this->keepReturn) { - out = out.AppendString(u8"\t"); - out = out.Append(this->returns); - out = out.AppendString(u8" ret;\n"); - } - out = out.AppendString(u8"\tDWORD lasterr;\n"); - out = out.AppendString(u8"\n"); - - if (this->keepReturn) { - out = out.AppendString(u8"\tif (ret == NULL)\n"); - out = out.AppendString(u8"\t\treturn E_POINTER;\n"); - } - - out = out.AppendString(u8"\tSetLastError(0);\n"); - out = out.AppendString(u8"\t"); - if (this->keepReturn) - out = out.AppendString(u8"*"); - out = out.AppendString(u8"ret = "); - out = out.Append(this->Call()); - out = out.AppendString(u8";\n"); - out = out.AppendString(u8"\tlasterr = GetLastError();\n"); - - out = out.AppendString(u8"\tif ("); - if (this->keepReturn) - out = out.AppendString(u8"*"); - out = out.AppendString(u8"ret "); - out = out.Append(this->cond[0]); - out = out.AppendString(u8" "); - out = out.Append(this->cond[1]); - out = out.AppendString(u8")\n"); - out = out.AppendString(u8"\t\treturn lastErrorToHRESULT(lasterr, \""); - out = out.Append(this->name); - out = out.AppendString(u8"()\");\n"); - out = out.AppendString(u8"\treturn S_OK;\n"); - - out = out.AppendString(u8"}"); - return out; -} - -class Processor { - bool previousLineBlank; - - ByteSlice generate(ByteSlice line); -public: - Processor(void); - - ByteSlice Process(ByteSlice line); -}; - -Processor::Processor(void) -{ - this->previousLineBlank = false; -} - -#define noutbuf 2048 - -ByteSlice Processor::generate(ByteSlice line) -{ - ByteSlice genout; - Function *f; - - genout = ByteSlice(0, noutbuf); - if (!this->previousLineBlank) - genout = genout.AppendString("\n"); - - f = new Function(line); - genout = genout.Append(f->Signature()); - genout = genout.AppendString(u8"\n"); - genout = genout.Append(f->Body()); - delete f; - - genout = genout.AppendString(u8"\n"); - this->previousLineBlank = false; - return genout; -} - -ByteSlice Processor::Process(ByteSlice line) -{ - if (line.Len() > 0 && line.Data()[0] == '@') - return this->generate(line.Slice(1, line.Len())); - if (line.Len() == 0) { - if (this->previousLineBlank) - return ByteSlice(); - this->previousLineBlank = true; - } else - this->previousLineBlank = false; - return line.AppendString("\n"); -} - -} - -int main(int argc, char *argv[]) -{ - ReadCloser *fin = NULL; - WriteCloser *fout = NULL; - Scanner *s = NULL; - Processor p; - ByteSlice b; - int ret = 1; - Error *err = NULL; - - if (argc != 3) { - fprintf(stderr, "usage: %s infile outfile\n", argv[0]); - return 1; - } - - err = OpenRead(argv[1], &fin); - if (err != NULL) { - fprintf(stderr, "error opening %s: %s\n", argv[1], err->String()); - goto done; - } - err = CreateWrite(argv[2], &fout); - if (err != NULL) { - fprintf(stderr, "error creating %s: %s\n", argv[2], err->String()); - goto done; - } - - s = new Scanner(fin); - while (s->Scan()) { - b = p.Process(s->Bytes()); - err = fout->Write(b); - if (err != NULL) { - fprintf(stderr, "error writing to %s: %s\n", argv[2], err->String()); - goto done; - } - } - err = s->Err(); - if (err != NULL) { - fprintf(stderr, "error reading from %s: %s\n", argv[1], err->String()); - err = NULL; // we don't own err here - goto done; - } - - ret = 0; -done: - if (s != NULL) - delete s; - if (fout != NULL) - delete fout; - if (fin != NULL) - delete fin; - if (err != NULL) - delete err; - return ret; -} diff --git a/windows/tools/lib.cpp b/windows/tools/lib.cpp deleted file mode 100644 index da12dede..00000000 --- a/windows/tools/lib.cpp +++ /dev/null @@ -1,349 +0,0 @@ -// 21 may 2018 -#ifdef _WIN32 -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 -#include -#include -#define openfunc _open -#define openflags (_O_RDONLY | _O_BINARY) -#define openmode (_S_IREAD) -#define readfunc _read -#define readtype int -#define closefunc _close -#else -#endif -#include -#include -#include -#include -#include -#include "lib.hpp" - -class eofError : public Error { -public: - virtual ~eofError(void); - - virtual const char *String(void) const; -}; - -eofError::~eofError(void) -{ - // do nothing -} - -const char *eofError::String(void) const -{ - return "EOF"; -} - -class shortWriteError : public Error { -public: - virtual ~shortWriteError(void); - - virtual const char *String(void) const; -}; - -shortWriteError::~shortWriteError(void) -{ - // do nothing -} - -const char *shortWriteError::String(void) const -{ - return "short write"; -} - -Error *NewEOF(void) -{ - return new eofError; -} - -Error *NewErrShortWrite(void) -{ - return new shortWriteError; -} - -bool IsEOF(Error *e) -{ - // typeid does not work directly with pointers, alas (see https://stackoverflow.com/questions/4202877/typeid-for-polymorphic-types) - return typeid (*e) == typeid (eofError); -} - -namespace { - -struct sliceAlloc { - char *b; - size_t n; - uintmax_t refcount; -}; - -std::map sliceAllocs; - -char *sliceAlloc(size_t n) -{ - struct sliceAlloc sa; - - sa.b = new char[n]; - sa.n = n; - sa.refcount = 1; - sliceAllocs[(uintptr_t) (sa.b)] = sa; - return sa.b; -} - -uintptr_t sliceLookup(char *b) -{ - return sliceAllocs.lower_bound((uintptr_t) b)->first; -} - -void sliceRetain(char *b) -{ - if (b == NULL) - return; - sliceAllocs[sliceLookup(b)].refcount++; -} - -void sliceRelease(char *b) -{ - uintptr_t key; - - if (b == NULL) - return; - key = sliceLookup(b); - sliceAllocs[key].refcount--; - if (sliceAllocs[key].refcount == 0) { - delete[] sliceAllocs[key].b; - sliceAllocs.erase(key); - } -} - -} - -ByteSlice::ByteSlice(void) -{ - this->data = NULL; - this->len = 0; - this->cap = 0; -} - -ByteSlice::ByteSlice(const ByteSlice &b) -{ - this->data = b.data; - sliceRetain(this->data); - this->len = b.len; - this->cap = b.cap; -} - -ByteSlice::ByteSlice(ByteSlice &&b) -{ - this->data = b.data; - b.data = NULL; - this->len = b.len; - b.len = 0; - this->cap = b.cap; - b.cap = 0; -} - -ByteSlice::ByteSlice(const char *b, size_t n) -{ - this->data = sliceAlloc(n); - memcpy(this->data, b, n * sizeof (char)); - this->len = n; - this->cap = n; -} - -ByteSlice::ByteSlice(size_t len, size_t cap) -{ - this->data = sliceAlloc(cap); - memset(this->data, 0, len * sizeof (char)); - this->len = len; - this->cap = cap; -} - -ByteSlice::ByteSlice(int len, size_t cap) : - ByteSlice::ByteSlice((size_t) len, cap) -{ - // do nothing else -} - -ByteSlice::~ByteSlice(void) -{ - sliceRelease(this->data); -} - -ByteSlice &ByteSlice::operator=(const ByteSlice &b) -{ - this->data = b.data; - sliceRetain(this->data); - this->len = b.len; - this->cap = b.cap; - return *this; -} - -ByteSlice &ByteSlice::operator=(ByteSlice &&b) -{ - this->data = b.data; - b.data = NULL; - this->len = b.len; - b.len = 0; - this->cap = b.cap; - b.cap = 0; - return *this; -} - -char *ByteSlice::Data(void) -{ - return this->data; -} - -const char *ByteSlice::Data(void) const -{ - return this->data; -} - -size_t ByteSlice::Len(void) const -{ - return this->len; -} - -size_t ByteSlice::Cap(void) const -{ - return this->cap; -} - -ByteSlice ByteSlice::Slice(size_t start, size_t end) -{ - ByteSlice b; - - b.data = this->data + start; - sliceRetain(b.data); - b.len = end - start; - b.cap = this->cap - start; - return b; -} - -ByteSlice ByteSlice::Append(const char *b, size_t n) -{ - ByteSlice s; - - if (this->len + n < this->cap) { - s.data = this->data; - sliceRetain(s.data); - s.len = this->len + n; - s.cap = this->cap; - memcpy(s.data + this->len, b, n * sizeof (char)); - return s; - } - s.data = sliceAlloc(this->len + n); - memcpy(s.data, this->data, this->len * sizeof (char)); - memcpy(s.data + this->len, b, n * sizeof (char)); - s.len = this->len + n; - s.cap = this->len + n; - return s; -} - -ByteSlice ByteSlice::Append(const ByteSlice &b) -{ - return this->Append(b.data, b.len); -} - -ByteSlice ByteSlice::AppendString(const char *str) -{ - return this->Append(str, strlen(str)); -} - -void ByteSlice::CopyFrom(const char *b, size_t n) -{ - n = std::min(this->len, n); - memcpy(this->data, b, n); -} - -void ByteSlice::CopyFrom(const ByteSlice &b) -{ - this->CopyFrom(b.data, b.len); -} - -#define nbuf 1024 - -Scanner::Scanner(ReadCloser *r) -{ - this->r = r; - this->buf = ByteSlice(nbuf, nbuf); - this->p = ByteSlice(); - this->line = ByteSlice(0, nbuf); - this->err = NULL; -} - -Scanner::~Scanner(void) -{ - if (this->err != NULL) - delete this->err; -} - -bool Scanner::Scan(void) -{ - size_t n; - - if (this->err != NULL) - return false; - this->line = this->line.Slice(0, 0); - for (;;) { - if (this->p.Len() > 0) { - size_t j; - bool haveline; - - haveline = false; - for (j = 0; j < this->p.Len(); j++) - if (this->p.Data()[j] == '\n') { - haveline = true; - break; - } - this->line = this->line.Append(this->p.Slice(0, j)); - this->p = this->p.Slice(j, this->p.Len()); - if (haveline) { - // swallow the \n for the next time through - this->p = this->p.Slice(1, this->p.Len()); - return true; - } - // otherwise, the buffer was exhausted in the middle of a line, so fall through - } - // need to refill the buffer - this->err = this->r->Read(this->buf, &n); - if (this->err != NULL) - return false; - this->p = this->buf.Slice(0, n); - } -} - -ByteSlice Scanner::Bytes(void) const -{ - return this->line; -} - -Error *Scanner::Err(void) const -{ - if (!IsEOF(this->err)) - return this->err; - return NULL; -} - -std::vector ByteSliceFields(ByteSlice s) -{ - std::vector ret; - const char *data; - size_t i, j; - - data = s.Data(); - i = 0; - while (i < s.Len()) { - if (data[i] == ' ' || data[i] == '\t') { - i++; - continue; - } - for (j = i + 1; j < s.Len(); j++) - if (data[j] == ' ' || data[j] == '\t') - break; - ret.push_back(s.Slice(i, j)); - i = j; - } - return ret; -} diff --git a/windows/tools/lib.hpp b/windows/tools/lib.hpp deleted file mode 100644 index 417d6fbf..00000000 --- a/windows/tools/lib.hpp +++ /dev/null @@ -1,80 +0,0 @@ -// 21 may 2018 -#include - -class Error { -public: - virtual ~Error(void) = default; - - virtual const char *String(void) const = 0; -}; - -extern Error *NewEOF(void); -extern Error *NewErrShortWrite(void); -extern bool IsEOF(Error *e); - -// super lightweight (can be passed by value without any data being copied) wrapper around an array of bytes that can be sliced further without copying (std::vector can't do that easily) -// this is modelled after Go's slices -class ByteSlice { - char *data; - size_t len; - size_t cap; -public: - ByteSlice(void); // default constructor; equivalent to Go's nil slice - ByteSlice(const ByteSlice &b); // copy constructor - ByteSlice(ByteSlice &&b); // move constructor; sets b to ByteSlice() - ByteSlice(const char *b, size_t n); - ByteSlice(size_t len, size_t cap); - ByteSlice(int len, size_t cap); // deal with stupid rule about 0 (see https://stackoverflow.com/a/4610586/3408572) - ~ByteSlice(void); - - // note: copy assignment does not use copy-and-swap because I get neither copy-and-swap nor ADL public friend swap functions (https://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom, https://stackoverflow.com/questions/5695548/public-friend-swap-member-function) - // (and also [14:55:04] i don't see why you'd need swap-on-copy semantics for anything if you're really just trying to make copy assignments create two references to the same memory) - ByteSlice &operator=(const ByteSlice &b); // copy assignment - ByteSlice &operator=(ByteSlice &&b); // move assignment; sets b to ByteSlice() - - char *Data(void); - const char *Data(void) const; - size_t Len(void) const; - size_t Cap(void) const; - - ByteSlice Slice(size_t start, size_t end); - ByteSlice Append(const char *b, size_t n); - ByteSlice Append(const ByteSlice &b); - ByteSlice AppendString(const char *str); - void CopyFrom(const char *b, size_t n); - void CopyFrom(const ByteSlice &b); -}; - -class ReadCloser { -public: - virtual ~ReadCloser(void) = default; - - virtual Error *Read(ByteSlice b, size_t *n) = 0; -}; - -class WriteCloser { -public: - virtual ~WriteCloser(void) = default; - - virtual Error *Write(const ByteSlice b) = 0; -}; - -extern Error *OpenRead(const char *filename, ReadCloser **r); -extern Error *CreateWrite(const char *filename, WriteCloser **w); - -class Scanner { - ReadCloser *r; - ByteSlice buf; - ByteSlice p; - ByteSlice line; - Error *err; -public: - Scanner(ReadCloser *r); - ~Scanner(void); - - bool Scan(void); - ByteSlice Bytes(void) const; - Error *Err(void) const; -}; - -extern std::vector ByteSliceFields(ByteSlice s); diff --git a/windows/tools/lib_posix.cpp b/windows/tools/lib_posix.cpp deleted file mode 100644 index 1bd855cf..00000000 --- a/windows/tools/lib_posix.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// 25 may 2018 -#include -#include -#include -#include -#include "lib.hpp" - -class posixError : public Error { - int error; -public: - posixError(int error); - virtual ~posixError(void); - - virtual const char *String(void) const; -}; - -posixError::posixError(int error) -{ - this->error = error; -} - -posixError::~posixError(void) -{ - // do nothing -} - -const char *posixError::String(void) const -{ - return strerror(this->error); -} - -class posixReadCloser : public ReadCloser { - int fd; -public: - posixReadCloser(int fd); - virtual ~posixReadCloser(void); - - virtual Error *Read(ByteSlice b, size_t *n); -}; - -posixReadCloser::posixReadCloser(int fd) -{ - this->fd = fd; -} - -posixReadCloser::~posixReadCloser(void) -{ - close(this->fd); -} - -Error *posixReadCloser::Read(ByteSlice b, size_t *n) -{ - ssize_t ret; - - *n = 0; - ret = read(this->fd, b.Data(), b.Len()); - if (ret < 0) - return new posixError(errno); - if (ret == 0) - return NewEOF(); - *n = ret; - return NULL; -} - -class posixWriteCloser : public WriteCloser { - int fd; -public: - posixWriteCloser(int fd); - virtual ~posixWriteCloser(void); - - virtual Error *Write(const ByteSlice b); -}; - -posixWriteCloser::posixWriteCloser(int fd) -{ - this->fd = fd; -} - -posixWriteCloser::~posixWriteCloser(void) -{ - close(this->fd); -} - -Error *posixWriteCloser::Write(const ByteSlice b) -{ - ssize_t ret; - - ret = write(this->fd, b.Data(), b.Len()); - if (ret < 0) - return new posixError(errno); - if (((size_t) ret) != b.Len()) - return NewErrShortWrite(); - return NULL; -} - -Error *OpenRead(const char *filename, ReadCloser **r) -{ - int fd; - - *r = NULL; - fd = open(filename, O_RDONLY, 0644); - if (fd < 0) - return new posixError(errno); - *r = new posixReadCloser(fd); - return NULL; -} - -Error *CreateWrite(const char *filename, WriteCloser **w) -{ - int fd; - - *w = NULL; - fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd < 0) - return new posixError(errno); - *w = new posixWriteCloser(fd); - return NULL; -} From f1d9e36a0ea276f90aea50db4363c1a8ec3ae6ec Mon Sep 17 00:00:00 2001 From: Pietro Gagliardi Date: Sat, 5 Jan 2019 18:56:04 -0500 Subject: [PATCH 30/30] Abandon the current work on windows-namespace-and-hresult-cleanup. I'll take a different approach. --- windows/tools/a | 55 ------------- windows/tools/cpp.template | 29 ------- windows/tools/funclist.textpb | 134 -------------------------------- windows/tools/gen.sh | 1 - windows/tools/hresultwrap.go | 70 ----------------- windows/tools/hresultwrap.proto | 18 ----- windows/tools/mk.sh | 3 - 7 files changed, 310 deletions(-) delete mode 100644 windows/tools/a delete mode 100644 windows/tools/cpp.template delete mode 100644 windows/tools/funclist.textpb delete mode 100755 windows/tools/gen.sh delete mode 100644 windows/tools/hresultwrap.go delete mode 100644 windows/tools/hresultwrap.proto delete mode 100755 windows/tools/mk.sh diff --git a/windows/tools/a b/windows/tools/a deleted file mode 100644 index 5be22d75..00000000 --- a/windows/tools/a +++ /dev/null @@ -1,55 +0,0 @@ -@BOOL GetWindowPlacement HWND hwnd uiprivLPWWINDOWPLACEMENT wp == 0 -$typedef const WINDOWPLACEMENT *uiprivLPCWINDOWPLACEMENT; -@BOOL SetWindowPlacement HWND hwnd uiprivLPCWINDOWPLACEMENT wp == 0 -@HWND SetParent HWND hwnd HWND newParent == NULL -@BOOL GetClientRect HWND hwnd LPRECT r == 0 -@BOOL GetWindowRect HWND hwnd LPRECT r == 0 -@int GetClassNameW HWND hwnd LPWSTR name int n == 0 - -@BOOL SetWindowSubclass HWND hwnd SUBCLASSPROC proc UINT_PTR id DWORD_PTR dwRefData == FALSE -@BOOL RemoveWindowSubclass HWND hwnd SUBCLASSPROC proc UINT_PTR id == FALSE - -@*HWND CreateDialogIndirectParamW HINSTANCE hInstance LPCDLGTEMPLATE dialog HWND parent DLGPROC proc LPARAM param == NULL -// note: this gives dialogs in libui the condition that they must NOT call uiprivTODOEndDialog() with a negative result code -@*INT_PTR DialogBoxIndirectParamW HINSTANCE hInstance LPCDLGTEMPLATE dialog HWND parent DLGPROC proc LPARAM param < 0 -@BOOL EndDialog HWND hdlg INT_PTR result == 0 -@*HWND GetDlgItem HWND hdlg int id == NULL - -@*HMENU CreateMenu == NULL -@*HMENU CreatePopupMenu == NULL -@BOOL AppendMenuW HMENU menu UINT flags UINT_PTR id LPCWSTR text == 0 -@BOOL SetMenu HWND hwnd HMENU menu == 0 -@BOOL GetMenuItemInfoW HMENU menu UINT item BOOL byPosition LPMENUITEMINFO info == 0 -@BOOL SetMenuItemInfoW HMENU menu UINT item BOOL byPosition LPMENUITEMINFO info == 0 - -@*HDC BeginPaint HWND hwnd LPPAINTSTRUCT ps == NULL -@*HDC GetDC HWND hwnd == NULL -@int ReleaseDC HWND hwnd HDC dc == 0 -@*HDC CreateCompatibleDC HDC dc == NULL -@BOOL DeleteDC HDC dc == 0 -$typedef const RECT *uiprivLPCRECT; -@BOOL InvalidateRect HWND hwnd uiprivLPCRECT r BOOL erase == 0 -@BOOL ValidateRect HWND hwnd uiprivLPCRECT r == 0 - -@*HBITMAP CreateCompatibleBitmap HDC dc int width int height == NULL -@*HBRUSH CreatePatternBrush HBITMAP bitmap == NULL -@BOOL DeleteObject HGDIOBJ obj == 0 - -@BOOL SetBrushOrgEx HDC dc int x int y LPPOINT prev == 0 -@int SetBkMode HDC dc int mode == 0 -@BOOL BitBlt HDC dest int destX int destY int destWidth int destHeight HDC src int srcX int srcY DWORD op == 0 - -@BOOL GetTextMetricsW HDC dc LPTEXTMETRIC tm == 0 -@BOOL APIENTRY GetTextExtentPoint32W HDC dc LPCWSTR str int n LPSIZE size == 0 - -@BOOL ReleaseCapture == 0 -@BOOL _TrackMouseEvent LPTRACKMOUSEEVENT tme == 0 - -@BOOL GetScrollInfo HWND hwnd int bar LPSCROLLINFO si == 0 - -@BOOL SystemParametersInfoW UINT action UINT param PVOID v UINT winini == 0 -@BOOL GetMonitorInfoW HMONITOR monitor LPMONITORINFO info == 0 - -@*int GetLocaleInfoEx LPCWSTR name LCTYPE type LPWSTR buf int n == 0 - -@BOOL UnhookWindowsHookEx HHOOK hook == 0 diff --git a/windows/tools/cpp.template b/windows/tools/cpp.template deleted file mode 100644 index a9627093..00000000 --- a/windows/tools/cpp.template +++ /dev/null @@ -1,29 +0,0 @@ -{{/* 8 august 2018 */}}// this file is generated by tools/hresultwrap and should NOT be modified directly -#include "uipriv_windows.hpp" - -static inline HRESULT lastErrorToHRESULT(DWORD lasterr, const char *funcname) -{ - HRESULT hr; - - hr = E_FAIL; - if (lasterr != 0) - hr = HRESULT_FROM_WIN32(lasterr); - uiprivImplBug("error calling %s: last error %I32d\n", funcname, lasterr); - return hr; -}{{range .}} - -{{$narg := len .Arg}}HRESULT {{if .CallingConvention}}{{.CallingConvention}}{{else}}WINAPI{{end}} uiprivHR{{.Name}}({{range $i, $a := .Arg}}{{$a}}{{argcomma $i $narg}}{{end}}{{if .Save}}, _Out_ {{.Ret}} *outRet{{end}}) -{ - {{.Ret}} xyzret; - DWORD xyzlasterr; - -{{if .Save}} if (outRet == NULL) - return E_POINTER; -{{end}} SetLastError(0); - xyzret = {{.Name}}({{range $i, $a := .Arg}}{{argname $a}}{{argcomma $i $narg}}{{end}}); - xyzlasterr = GetLastError(); -{{if .Save}} *outRet = xyzret; -{{end}} if (xyzret != {{.Failval}}) - return S_OK; - return lastErrToHRESULT(xyzlasterr, "{{.Name}}()"); -}{{/*TODO cleanup*/}}{{end}} diff --git a/windows/tools/funclist.textpb b/windows/tools/funclist.textpb deleted file mode 100644 index c876732a..00000000 --- a/windows/tools/funclist.textpb +++ /dev/null @@ -1,134 +0,0 @@ -# 8 august 2018 - -# TODO preserve lpRect on failure -func: { -name: "AdjustWindowRectEx" -arg: "_Inout_ LPRECT lpRect" -arg: "_In_ DWORD dwStyle" -arg: "_In_ BOOL bMenu" -arg: "_In_ DWORD dwExStyle" -ret: "BOOL" -failval: "0" -} - -func: { -name: "CreateWindowExW" -arg: "_In_ DWORD dwExStyle" -arg: "_In_opt_ LPCWSTR lpClassName" -arg: "_In_opt_ LPCWSTR lpWindowName" -arg: "_In_ DWORD dwStyle" -arg: "_In_ int X" -arg: "_In_ int Y" -arg: "_In_ int nWidth" -arg: "_In_ int nHeight" -arg: "_In_opt_ HWND hWndParent" -arg: "_In_opt_ HMENU hMenu" -arg: "_In_opt_ HINSTANCE hInstance" -arg: "_In_opt_ LPVOID lpParam" -ret: "HWND" -failval: "NULL" -save: true -} - -func: { -name: "DestroyWindow" -arg: "_In_ HWND hWnd" -ret: "BOOL" -failval: "0" -cleanup: true -} - -# TODO failexpr is < 0 -func: { -name: "GetMessageW" -arg: "_Out_ LPMSG lpMsg" -arg: "_In_opt_ HWND hWnd" -arg: "_In_ UINT wMsgFilterMin" -arg: "_In_ UINT wMsgFilterMax" -ret: "BOOL" -failval: "-1" -} - -# TODO write a L'\0' to lpString[0] on failure -# TODO also add extra checks to make sure lpString is not NULL -func: { -name: "GetWindowTextW" -arg: "_In_ HWND hWnd" -arg: "_Out_writes_(nMaxCount) LPWSTR lpString" -arg: "_In_ int nMaxCount" -ret: "int" -failval: "0" -} - -func: { -name: "KillTimer" -arg: "_In_opt_ HWND hWnd" -arg: "_In_ UINT_PTR uIDEvent" -ret: "BOOL" -failval: "0" -} - -func: { -name: "PostMessageW" -arg: "_In_opt_ HWND hWnd" -arg: "_In_ UINT Msg" -arg: "_In_ WPARAM wParam" -arg: "_In_ LPARAM lParam" -ret: "BOOL" -failval: "0" -} - -func: { -name: "RegisterClassW" -arg: "_In_ CONST WNDCLASSW *lpWndClass" -ret: "ATOM" -failval: "0" -save: true -} - -func: { -name: "SetTimer" -arg: "_In_opt_ HWND hWnd" -arg: "_In_ UINT_PTR nIDEvent" -arg: "_In_ UINT uElapse" -arg: "_In_opt_ TIMERPROC lpTimerFunc" -ret: "UINT_PTR" -failval: "0" -} - -func: { -name: "SetWindowPos" -arg: "_In_ HWND hWnd" -arg: "_In_opt_ HWND hWndInsertAfter" -arg: "_In_ int X" -arg: "_In_ int Y" -arg: "_In_ int cx" -arg: "_In_ int cy" -arg: "_In_ UINT uFlags" -ret: "BOOL" -failval: "0" -} - -func: { -name: "SetWindowTextW" -arg: "_In_ HWND hWnd" -arg: "_In_opt_ LPCWSTR lpString" -ret: "BOOL" -failval: "0" -} - -func: { -name: "UnregisterClassW" -arg: "_In_ LPCWSTR lpClassName" -arg: "_In_opt_ HINSTANCE hInstance" -ret: "BOOL" -failval: "0" -cleanup: true -} - -func: { -name: "UpdateWindow" -arg: "_In_ HWND hWnd" -ret: "BOOL" -failval: "0" -} diff --git a/windows/tools/gen.sh b/windows/tools/gen.sh deleted file mode 100755 index 168df8fa..00000000 --- a/windows/tools/gen.sh +++ /dev/null @@ -1 +0,0 @@ -./hresultwrap funclist.textpb cpp.template diff --git a/windows/tools/hresultwrap.go b/windows/tools/hresultwrap.go deleted file mode 100644 index edf9e6b2..00000000 --- a/windows/tools/hresultwrap.go +++ /dev/null @@ -1,70 +0,0 @@ -// 8 august 2018 -// usage: hresultwrap funclist template out -package main - -import ( - "fmt" - "os" - "io/ioutil" - "text/template" - "strings" - - "github.com/golang/protobuf/proto" -) - -func argname(arg string) string { - fields := strings.Fields(arg) - last := fields[len(fields) - 1] - start := strings.LastIndexFunc(last, func(r rune) bool { - return !(r >= 'A' && r <= 'Z') && - !(r >= 'a' && r <= 'z') && - !(r >= '0' && r <= '9') && - r != '_' - }) - if start == -1 { - return last - } - // TODO replace + 1 with + len of that last rune - return last[start + 1:] -} - -func argcomma(n, len int) string { - if n == len - 1 { - return "" - } - return ", " -} - -var templateFuncs = template.FuncMap{ - "argname": argname, - "argcomma": argcomma, -} - -func main() { - if len(os.Args) != 3 { - fmt.Fprintf(os.Stderr, "usage: %s funclist template\n", os.Args[0]) - os.Exit(1) - } - b, err := ioutil.ReadFile(os.Args[1]) - if err != nil { - fmt.Fprintf(os.Stderr, "error reading %s: %v\n", os.Args[1], err) - os.Exit(1) - } - var f File - err = proto.UnmarshalText(string(b), &f) - if err != nil { - fmt.Fprintf(os.Stderr, "error parsing %s: %v\n", os.Args[1], err) - os.Exit(1) - } - - tmpl, err := template.New(os.Args[2]).Funcs(templateFuncs).ParseFiles(os.Args[2]) - if err != nil { - fmt.Fprintf(os.Stderr, "error parsing %s: %v\n", os.Args[2], err) - os.Exit(1) - } - err = tmpl.Execute(os.Stdout, f.Func) - if err != nil { - fmt.Fprintf(os.Stderr, "error executing template: %v\n", err) - os.Exit(1) - } -} diff --git a/windows/tools/hresultwrap.proto b/windows/tools/hresultwrap.proto deleted file mode 100644 index 07801212..00000000 --- a/windows/tools/hresultwrap.proto +++ /dev/null @@ -1,18 +0,0 @@ -// 8 august 2018 -syntax = "proto3"; - -option go_package = "main"; - -message File { - repeated Function func = 1; -} - -message Function { - string name = 1; - string calling_convention = 2; // defaults to WINAPI - repeated string arg = 3; - string ret = 4; - string failval = 5; - bool save = 6; - bool cleanup = 7; -} diff --git a/windows/tools/mk.sh b/windows/tools/mk.sh deleted file mode 100755 index 276c3aae..00000000 --- a/windows/tools/mk.sh +++ /dev/null @@ -1,3 +0,0 @@ -rm -f hresultwrap.pb.go hresultwrap && -protoc --go_out=. hresultwrap.proto && -go build hresultwrap.go hresultwrap.pb.go