// 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; }