#include "cmdline.h" #include #include #include #include extern char STSbuf[256]; static int ioLineNum; static Boolean printedAnything; static char arrowBuf[256]; static Boolean newErr; static Boolean newSrc; static Boolean srcIsErr; static OSSpec errSpec; static OSSpec srcSpec; static Boolean validErr; static Boolean validSrc; static SInt32 lastPrintingPlugin; static Boolean ioInHelp; static Boolean ioPiping; static void catchinterrupt() { clState.userBreak = 1; } static void SetupConsoleInfo(void) { struct winsize ws; struct stat st; signal(SIGINT, catchinterrupt); ioPiping = 0; fstat(stdout->_file, &st); if (st.st_mode & 0x1000) ioPiping = 1; fstat(stderr->_file, &st); if (st.st_mode & 0x1000) ioPiping = 1; if (ioPiping) { ws.ws_row = 0; ws.ws_col = 80; } else if (ioctl(stdout->_file, TIOCGWINSZ, &ws) < 0) { ioPiping = 1; ws.ws_row = 0; ws.ws_col = 80; } optsEnvir.rows = ws.ws_row; optsEnvir.cols = ws.ws_col; if (optsEnvir.cols > 256) optsEnvir.cols = 256; } static void Crash() { *((unsigned char *) NULL) = 0; } void SetupDebuggingTraps(void) { signal(SIGABRT, Crash); } Boolean IO_Initialize(void) { ioPiping = 0; ioInHelp = 0; ioLineNum = 0; SetupConsoleInfo(); if (ioPiping) { setvbuf(stdout, NULL, 0, 1024); setvbuf(stderr, NULL, 0, 1024); } else { setvbuf(stdout, NULL, 1, 1024); setvbuf(stderr, NULL, 1, 1024); } InitWorking(); return 1; } Boolean IO_Terminate(void) { if (ioInHelp) IO_HelpTerminate(); TermWorking(); return 1; } Boolean IO_HelpInitialize(void) { ioInHelp = 1; return 1; } Boolean IO_HelpTerminate(void) { ioInHelp = 0; return 1; } static Boolean SendHandleToFile(FILE *file, Handle text, SInt32 size) { Boolean ret; char *ptr; char *lineEnd; char *end; if (file != stdout && file != stderr) setvbuf(file, NULL, 0, 1024); HLock(text); ptr = *text; if (size && ptr[size - 1] == 0) size--; if (size <= 0) { ret = 1; } else { end = ptr + size; while (ptr < end) { lineEnd = ptr; while (lineEnd < end && *lineEnd != '\n' && *lineEnd != '\r') lineEnd++; if (lineEnd - ptr) { if (fwrite(ptr, lineEnd - ptr, 1, file) != 1) { CLReportCError(10, errno); ret = 0; goto fail; } } if (CheckForUserBreak()) { ret = 1; goto fail; } // I have a hunch that this "\n" might be a define if (fwrite("\n", strlen("\n"), 1, file) != 1) { CLReportCError(10, errno); ret = 0; goto fail; } if (lineEnd < end && *(lineEnd++) == '\r' && *lineEnd == '\n') ++lineEnd; ptr = lineEnd; } ret = 1; } fail: HUnlock(text); fflush(file); if (file != stdout && file != stderr) setvbuf(file, NULL, 2, 1024); return ret; } void FixHandleForIDE(Handle text, UInt32 size) { char *ptr; HLock(text); for (ptr = *text; ptr < (*text + size); ptr++) { if (*ptr == '\r') *ptr = '\n'; } HUnlock(text); } Boolean ShowHandle(Handle text, UInt32 size, Boolean decorate) { static const char *border = "===============\n"; if (decorate) fprintf(stdout, border); if (!SendHandleToFile(stdout, text, size)) return 0; if (decorate) fprintf(stdout, border); fflush(stdout); return 1; } Boolean WriteHandleToFile(OSSpec *spec, Handle text, UInt32 size, OSType creator, OSType type) { FILE *file; char path[256]; OS_SpecToString(spec, path, sizeof(path)); file = fopen(path, "w+b"); if (!file) { CLReportCError(8, errno, path); return 0; } SendHandleToFile(file, text, size); fclose(file); OS_SetMacFileCreatorAndType(spec, creator, type); return 1; } Boolean WriteBinaryHandleToFile(OSSpec *spec, CWDataType maccreator, CWDataType mactype, OSHandle *text) { int err; OSFileHandle file; if ((err = OS_NewFileHandle(spec, text, 1, &file)) || (err = OS_FreeFileHandle(&file)) || (err = OS_SetMacFileCreatorAndType(spec, maccreator, mactype))) { CLReportOSError(8, err, OS_SpecToString(spec, STSbuf, sizeof(STSbuf))); return 0; } return 1; } Boolean AppendHandleToFile(OSSpec *spec, Handle text, UInt32 size, CWDataType maccreator, CWDataType mactype) { FILE *file; char path[256]; OS_SpecToString(spec, path, sizeof(path)); file = fopen(path, "a+b"); if (!file) { CLReportCError(8, errno, path); return 0; } SendHandleToFile(file, text, size); fclose(file); OS_SetMacFileCreatorAndType(spec, maccreator, mactype); return 1; } void InitWorking(void) { } void ShowWorking(int x) { } void TermWorking(void) { } static void ProgressFunction(const char *functionname) { if (optsCmdLine.verbose) CLReport(7, functionname); } Boolean CheckForUserBreak(void) { ShowWorking(4); return clState.userBreak; } typedef struct { char *buffer; int pos; int maxlen; SInt16 col; Boolean original; char *newline; } UnkCLIOStruct; // unknown names for these inlines CW_INLINE void appendText(UnkCLIOStruct *f, const char *str) { int len = strlen(str); if (f->pos + len >= f->maxlen) { f->maxlen = f->maxlen * 2 + len; if (f->original) { char *oldbuf; oldbuf = f->buffer; f->buffer = xmalloc("message buffer", f->maxlen); memcpy(f->buffer, oldbuf, f->pos); } else { f->buffer = xrealloc("message buffer", f->original ? NULL : f->buffer, f->maxlen); } f->original = 0; } memcpy(f->buffer + f->pos, str, len); f->pos += len; f->col += len; } CW_INLINE void appendChar(UnkCLIOStruct *f, char c) { if (f->pos >= f->maxlen) { f->maxlen *= 2; if (f->original) { char *oldbuf = f->buffer; f->buffer = xmalloc("message buffer", f->maxlen); memcpy(f->buffer, oldbuf, f->pos); } else { f->buffer = xrealloc("message buffer", f->buffer, f->maxlen); } f->original = 0; } f->buffer[f->pos++] = c; f->col++; } static void StartLine(UnkCLIOStruct *f) { f->col = 0; if (!optsEnvir.underIDE && f->newline) appendText(f, f->newline); } CW_INLINE void newLine(UnkCLIOStruct *f) { if (f->newline) appendChar(f, '\n'); else appendChar(f, ' '); StartLine(f); } static void WrapText(UnkCLIOStruct *f) { int wrapped; char wrapbuf[256]; char c; wrapped = 0; if (optsCmdLine.noWrapOutput) return; if (!f->newline) return; if (strlen(f->newline) > optsEnvir.cols / 2) return; while (wrapped < (optsEnvir.cols - 1) && f->col > strlen(f->newline)) { c = f->buffer[f->pos - 1]; if (c == ' ') break; if (c == '/') break; if (c == '-') break; wrapbuf[wrapped] = c; f->pos = f->pos - 1; f->col = f->col - 1; wrapped++; } if (f->col <= strlen(f->newline)) { while (f->col < (optsEnvir.cols - 1) && wrapped > 0) { appendChar(f, wrapbuf[--wrapped]); } } newLine(f); while (wrapped > 0 && f->maxlen > 0) { appendChar(f, wrapbuf[--wrapped]); } } static char *IO_VFormatText(char *buffer, SInt32 size, char *newline, const char *format, va_list ap) { UnkCLIOStruct f; char *arg; f.buffer = buffer; f.pos = 0; f.maxlen = size; f.col = 0; f.original = 1; f.newline = newline; StartLine(&f); while (*format && f.maxlen > 0) { if (*format == '%') { arg = va_arg(ap, char *); while (*arg && f.maxlen > 0) { if (*arg == '\r' || *arg == '\n') { newLine(&f); arg++; } else if (*arg == '\t') { if (f.maxlen > 0) { do { appendChar(&f, ' '); } while (f.col & 7); } arg++; } else { appendChar(&f, *(arg++)); if (!optsCmdLine.noWrapOutput && f.newline && f.col >= optsEnvir.cols - 1) WrapText(&f); } } format++; } else if (*format == '\r' || *format == '\n') { format++; newLine(&f); } else { appendChar(&f, *(format++)); if (!optsCmdLine.noWrapOutput && f.col >= optsEnvir.cols - 1) WrapText(&f); } } if (f.newline) { if (f.col == strlen(f.newline)) { f.pos -= f.col; f.col = 0; } } appendChar(&f, 0); return f.buffer; } char *IO_FormatText(char *buffer, SInt32 size, char *newline, const char *format, ...) { va_list ap; char *ret; va_start(ap, format); ret = IO_VFormatText(buffer, size, newline, format, ap); va_end(ap); return ret; } // TODO unify me with the one in the header enum { Msg_Note = 1, Msg_Warning = 2, Msg_Error = 3, Msg_Alert = 4, Msg_Status = 5 }; void CLPrintDispatch(int unk, SInt16 msgtype, const char *message) { FILE *out; const char *ptr; const char *nptr; if (optsCmdLine.stderr2stdout == 1 || msgtype == Msg_Note || msgtype == Msg_Status) out = stdout; else if (msgtype == Msg_Warning || msgtype == Msg_Error || msgtype == Msg_Alert) out = stderr; else OS_ASSERT(847, 0); if (!printedAnything && !ioPiping) { printedAnything = 1; ioLineNum = 0; } ptr = message; while (*ptr) { nptr = ptr; while (*nptr && *nptr != '\n' && *nptr != '\r') ++nptr; if (nptr - ptr) { if (fwrite(ptr, nptr - ptr, 1, out) != 1) clState.userBreak = 1; } if (*nptr) { ioLineNum++; fwrite("\n", strlen("\n"), 1, out); if (*nptr == '\r') nptr++; if (*nptr == '\n') nptr++; if (nptr[0] && !nptr[1] && (nptr[0] == '\n' || nptr[0] == '\r')) nptr++; } ptr = nptr; } if (out == stdout && optsCmdLine.verbose > 1) fflush(out); } static void GetFileInfo(MessageRef *ref) { if (ref) { srcIsErr = OS_EqualSpec(&ref->sourcefile, &ref->errorfile); if (!validSrc || !OS_EqualSpec(&ref->sourcefile, &srcSpec)) { newSrc = 1; srcSpec = ref->sourcefile; validSrc = 1; } else { newSrc = 0; } if (!validErr || !OS_EqualSpec(&ref->errorfile, &errSpec)) { newErr = 1; errSpec = ref->errorfile; validErr = 1; } else { newErr = 0; } } } static char *Arrows(MessageRef *ref) { int start; int len; arrowBuf[0] = 0; start = ref->tokenoffset; start %= optsEnvir.cols; if (start >= 0 && start < sizeof(arrowBuf)) { len = ref->tokenlength; if (len + start > sizeof(arrowBuf)) len = sizeof(arrowBuf) - start; if (len == 0) len = 1; memset(arrowBuf, ' ', start); memset(arrowBuf + start, '^', len); arrowBuf[start + len] = 0; } return arrowBuf; } static Boolean IsLikelyAnImporter(Plugin *plugin) { if (Plugin_CL_GetObjectFlags(plugin)->flags & 0x80000000) return 0; return plugin != Plugins_CL_MatchTarget(NULL, gTarg->cpu, gTarg->os, clState.plugintype, clState.language); } static char *GuessTool(Plugin *plugin) { if (plugin) { DropInFlags *df = Plugin_GetDropInFlags(plugin); switch (df->dropintype) { case CWDROPINDRIVERTYPE: return "Driver"; case CWDROPINPARSERTYPE: return "Usage"; case CWDROPINCOMPILERTYPE: if (df->edit_language == Lang_C_CPP || df->edit_language == Lang_Pascal) return "Compiler"; else if (df->edit_language == CWFOURCHAR('A','s','m',' ')) return "Assembler"; else if (IsLikelyAnImporter(plugin)) return "Importer"; else return "Compiler"; case CWDROPINLINKERTYPE: return "Linker"; } } return "Driver"; } static char *GuessDoing(Plugin *plugin) { if (plugin) { DropInFlags *df = Plugin_GetDropInFlags(plugin); switch (df->dropintype) { case CWDROPINPARSERTYPE: return "parsing"; case CWDROPINCOMPILERTYPE: return "compiling"; case CWDROPINLINKERTYPE: return "linking"; } } return "processing"; } static const char *msgnames[6] = { "", "Note", "Warning", "Error", "Alert", "Status" }; static const char *msgnames_gcc[6] = { "", " note", " warning", "", " alert", " status" }; static void styledMessage_MPW(Plugin *plugin, MessageRef *ref, SInt32 errorNumber, SInt16 msgType, const char *format, va_list va) { char msgBuf[256]; char *msgPtr; msgPtr = IO_VFormatText(msgBuf, sizeof(msgBuf), "# ", format, va); if (msgType != Msg_Status) CLPrintType(msgType, "### %s %s %s:\n", clState.programName, GuessTool(plugin), msgnames[msgType]); if (ref) { CLPrintType(msgType, "#\t%s\n", ref->sourceline); CLPrintType(msgType, "#\t%s\n", Arrows(ref)); } CLPrintDispatch(0, msgType, msgPtr); if (ref) { CLPrintType(msgType, "#----------------------------------------------------------\n"); CLPrintType(msgType, " File \"%s\"; Line %d\n", OS_SpecToString(&ref->errorfile, STSbuf, sizeof(STSbuf)), ref->linenumber); GetFileInfo(ref); if (!srcIsErr) CLPrintType(msgType, "#\twhile %s \"%s\"\n", GuessDoing(plugin), OS_SpecToString(&ref->sourcefile, STSbuf, sizeof(STSbuf))); CLPrintType(msgType, "#----------------------------------------------------------\n"); } if (msgPtr != msgBuf) free(msgPtr); } static void styledMessage_Default(Plugin *plugin, MessageRef *ref, SInt32 errorNumber, SInt16 msgType, const char *format, va_list va) { char lineBuf[320]; char msgBuf[256]; char *msgPtr; char *ptr; msgPtr = IO_VFormatText(msgBuf, sizeof(msgBuf), "# ", format, va); if (ref) { CLPrintType(msgType, "### %s %s:\n", clState.programName, GuessTool(plugin)); } else if (msgType != Msg_Status) { CLPrintType(msgType, "### %s %s %s:\n", clState.programName, GuessTool(plugin), msgnames[msgType]); } if (ref) { GetFileInfo(ref); if (newErr || (newSrc && srcIsErr)) { if (srcIsErr) { sprintf(lineBuf, "#%8s: %s\n", "File", OS_SpecToStringRelative(&errSpec, NULL, STSbuf, sizeof(STSbuf))); } else { sprintf(lineBuf, "#%8s: %s\n", "In", OS_SpecToStringRelative(&errSpec, NULL, STSbuf, sizeof(STSbuf))); } CLPrintDispatch(0, msgType, lineBuf); } if (newSrc && !srcIsErr) { sprintf(lineBuf, "# %7s: %s\n", "From", OS_SpecToStringRelative(&srcSpec, NULL, STSbuf, sizeof(STSbuf))); CLPrintDispatch(0, msgType, lineBuf); } if (newErr || newSrc) { ptr = &lineBuf[2]; while (*ptr && *ptr != '\n') *(ptr++) = '-'; *ptr = 0; if (ptr - lineBuf >= optsEnvir.cols - 1) lineBuf[optsEnvir.cols - 1] = 0; strcat(lineBuf, "\n"); CLPrintDispatch(0, msgType, lineBuf); } CLPrintType(msgType, "#%8d: %s\n", ref->linenumber, ref->sourceline); CLPrintType(msgType, "#%8s: %s\n", msgnames[msgType], Arrows(ref)); } CLPrintDispatch(0, msgType, msgPtr); if (msgPtr != msgBuf) free(msgPtr); } static void styledMessage_Terse(Plugin *plugin, MessageRef *ref, SInt32 errorNumber, SInt16 msgType, const char *format, va_list va) { char *msg; char *ptr; char msgBuf[256]; char *msgPtr; char header[256]; char *headPtr; char errBuf[256]; char *errPtr; if (ref) { if (msgnames_gcc[msgType][0]) { headPtr = mprintf( header, sizeof(header), "%s:%d:%s: ", OS_SpecToStringRelative(&ref->errorfile, NULL, STSbuf, sizeof(STSbuf)), ref->linenumber, msgnames_gcc[msgType] ); } else { headPtr = mprintf( header, sizeof(header), "%s:%d: ", OS_SpecToStringRelative(&ref->errorfile, NULL, STSbuf, sizeof(STSbuf)), ref->linenumber ); } } else if (msgType != Msg_Status) { headPtr = mprintf(header, sizeof(header), "%s: ", clState.programName); } else { header[0] = 0; headPtr = header; } msgPtr = IO_VFormatText(msgBuf, sizeof(msgBuf), headPtr, format, va); if ((strstr(msgPtr, "#warning") || strstr(msgPtr, "#error")) && ref->sourceline[0]) { errPtr = IO_FormatText(errBuf, sizeof(errBuf), headPtr, "%", ref->sourceline); } else { errPtr = 0; } if (headPtr != header) free(headPtr); msg = msgPtr; while (*msg) { ptr = msg; while (*ptr && *ptr != '\n') ptr++; CLPrintType(msgType, "%.*s\n", ptr - msg, msg); if (errPtr) { CLPrintType(msgType, "%s\n", errPtr); if (errPtr != errBuf) free(errPtr); errPtr = NULL; } if (*ptr) msg = ptr + 1; else msg = ptr; } if (msgPtr != msgBuf) free(msgPtr); } static void styledMessage_IDE(Plugin *plugin, MessageRef *ref, SInt32 errorNumber, SInt16 msgType, const char *format, va_list va) { char msgBuf[256]; char *msgPtr; SInt16 oldCols; oldCols = optsEnvir.cols; msgPtr = IO_VFormatText(msgBuf, sizeof(msgBuf), " ", format, va); optsEnvir.cols = oldCols; CLPrintType(msgType, "%8s : %s\n", msgnames[msgType], msgPtr + 11); if (msgPtr != msgBuf) free(msgPtr); if (ref) { msgPtr = IO_FormatText(msgBuf, sizeof(msgBuf), "\t", "%", ref->sourceline); CLPrintType(msgType, "%s line %d%s\n", OS_SpecToStringRelative(&ref->errorfile, NULL, STSbuf, sizeof(STSbuf)), ref->linenumber, msgPtr); if (msgPtr != msgBuf) free(msgPtr); } } static void styledMessage_Parseable(Plugin *plugin, MessageRef *ref, SInt32 errorNumber, SInt16 msgType, const char *format, va_list va) { char msgBuf[256]; char *msgPtr; CLPrintType(msgType, "%s|%s|%s\n", clState.programName, GuessTool(plugin), msgnames[msgType]); if (ref) { CLPrintType( msgType, "(%s|%d|%d|%d|%d|%d)\n", OS_SpecToString(&ref->errorfile, STSbuf, sizeof(STSbuf)), ref->linenumber, ref->tokenoffset, ref->tokenlength, ref->selectionoffset, ref->selectionlength ); CLPrintType(msgType, "=%s\n", ref->sourceline); } msgPtr = IO_VFormatText(msgBuf, sizeof(msgBuf), ">", format, va); CLPrintType(msgType, "%s\n", msgPtr); if (msgPtr != msgBuf) free(msgPtr); } void CLPrintType(SInt16 msgtype, const char *format, ...) { char printbuffer[256]; char *ptr; va_list va; va_start(va, format); ptr = mvprintf(printbuffer, sizeof(printbuffer), format, va); va_end(va); CLPrintDispatch(0, msgtype, ptr); if (ptr != printbuffer) free(ptr); } void CLPrint(const char *format, ...) { char printbuffer[256]; char *ptr; va_list va; va_start(va, format); ptr = mvprintf(printbuffer, sizeof(printbuffer), format, va); va_end(va); CLPrintDispatch(0, Msg_Note, ptr); if (ptr != printbuffer) free(ptr); } void CLPrintWarning(const char *format, ...) { char printbuffer[256]; char *ptr; va_list va; va_start(va, format); ptr = mvprintf(printbuffer, sizeof(printbuffer), format, va); va_end(va); CLPrintDispatch(0, Msg_Warning, ptr); if (ptr != printbuffer) free(ptr); } void CLPrintErr(const char *format, ...) { char printbuffer[256]; char *ptr; va_list va; va_start(va, format); ptr = mvprintf(printbuffer, sizeof(printbuffer), format, va); va_end(va); CLPrintDispatch(0, Msg_Error, ptr); if (ptr != printbuffer) free(ptr); } static void FixupMessageRef(MessageRef *ref) { char *bol; char *eol; int len; int scan; if (ref->sourceline && *ref->sourceline) { bol = ref->sourceline + ref->tokenoffset; eol = ref->sourceline + ref->tokenoffset + ref->tokenlength - 1; if (eol < bol) eol = bol; while (bol > ref->sourceline && bol[-1] != '\r') bol--; while (*eol && *eol != '\r' && *eol != '\n') eol++; len = eol - bol; ref->sourceline = xmalloc("text buffer", len + 1); strncpy(ref->sourceline, bol, len); ref->sourceline[len] = 0; for (scan = 0; scan < len; scan++) { if (ref->sourceline[scan] < ' ' || ref->sourceline[scan] >= 127) ref->sourceline[scan] = ' '; } } else { ref->sourceline = 0; } } SInt16 CLStyledMessageDispatch(Plugin *plugin, MessageRef *ref, SInt32 errorNumber, SInt16 msgType, const char *format, ...) { va_list va; MessageRef myref; UInt32 ptype; if (msgType == Msg_Warning) { ptype = plugin ? Plugin_GetPluginType(plugin) : CWDROPINDRIVERTYPE; if (optsCmdLine.noWarnings) return 0; if ((ptype == CWDROPINDRIVERTYPE || ptype == CWDROPINPARSERTYPE) && optsCmdLine.noCmdLineWarnings) return 0; if (optsCmdLine.warningsAreErrors) msgType = Msg_Error; } if (msgType == Msg_Error && clState.withholdErrors) return 0; if (msgType == Msg_Warning && clState.withholdWarnings) return 0; if (ref) { myref = *ref; FixupMessageRef(&myref); } va_start(va, format); if (optsCmdLine.msgStyle == 2) { styledMessage_MPW(plugin, ref ? &myref : 0, errorNumber, msgType, format, va); } else if (optsCmdLine.msgStyle == 1) { styledMessage_Terse(plugin, ref ? &myref : 0, errorNumber, msgType, format, va); } else if (optsCmdLine.msgStyle == 3) { styledMessage_IDE(plugin, ref ? &myref : 0, errorNumber, msgType, format, va); } else if (optsCmdLine.msgStyle == 4) { styledMessage_Parseable(plugin, ref ? &myref : 0, errorNumber, msgType, format, va); } else { styledMessage_Default(plugin, ref ? &myref : 0, errorNumber, msgType, format, va); } va_end(va); if (ref && myref.sourceline) xfree(myref.sourceline); if (msgType == Msg_Error && optsCmdLine.maxErrors) { if (++clState.countErrors >= optsCmdLine.maxErrors) { clState.withholdErrors = 1; if (!optsCompiler.noFail) { CLReport(70); clState.userBreak = 1; } else { CLReport(71); } } } if (msgType == Msg_Warning && optsCmdLine.maxWarnings) { if (++clState.countWarnings >= optsCmdLine.maxWarnings) { clState.withholdWarnings = 1; CLReport(72); } } return msgType; }