/* * $LynxId: HTAlert.c,v 1.101 2013/11/28 11:17:04 tom Exp $ * * Displaying messages and getting input for Lynx Browser * ========================================================== * * REPLACE THIS MODULE with a GUI version in a GUI environment! * * History: * Jun 92 Created May 1992 By C.T. Barker * Feb 93 Simplified, portablised TBL * */ #include #include #include #include #include #include #include #include #include #include /* store statusline messages */ #include #include #undef timezone /* U/Win defines this in time.h, hides implementation detail */ #if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H) #include #endif /* * 'napms()' is preferable to 'sleep()' in any case because it does not * interfere with output, but also because it can be less than a second. */ #ifdef HAVE_NAPMS #define LYSleep(n) napms(n) #else #define LYSleep(n) sleep((unsigned)n) #endif /* Issue a message about a problem. HTAlert() * -------------------------------- */ void HTAlert(const char *Msg) { CTRACE((tfp, "\nAlert!: %s\n\n", Msg)); CTRACE_FLUSH(tfp); _user_message(ALERT_FORMAT, Msg); LYstore_message2(ALERT_FORMAT, Msg); if (dump_output_immediately && dump_to_stderr) { fflush(stdout); fprintf(stderr, ALERT_FORMAT, Msg); fputc('\n', stderr); fflush(stderr); } LYSleepAlert(); } void HTAlwaysAlert(const char *extra_prefix, const char *Msg) { if (!dump_output_immediately && LYCursesON) { HTAlert(Msg); } else { if (extra_prefix) { fprintf(((TRACE) ? stdout : stderr), "%s %s!\n", extra_prefix, Msg); fflush(stdout); LYstore_message2(ALERT_FORMAT, Msg); LYSleepAlert(); } else { fprintf(((TRACE) ? stdout : stderr), ALERT_FORMAT, NonNull(Msg)); fflush(stdout); LYstore_message2(ALERT_FORMAT, Msg); LYSleepAlert(); fprintf(((TRACE) ? stdout : stderr), "\n"); } CTRACE((tfp, "\nAlert!: %s\n\n", Msg)); CTRACE_FLUSH(tfp); } } /* Issue an informational message. HTInfoMsg() * -------------------------------- */ void HTInfoMsg(const char *Msg) { _statusline(Msg); if (non_empty(Msg)) { CTRACE((tfp, "Info message: %s\n", Msg)); LYstore_message(Msg); LYSleepInfo(); } } void HTInfoMsg2(const char *Msg2, const char *Arg) { _user_message(Msg2, Arg); if (non_empty(Msg2)) { CTRACE((tfp, "Info message: ")); CTRACE((tfp, Msg2, Arg)); CTRACE((tfp, "\n")); LYstore_message2(Msg2, Arg); LYSleepInfo(); } } /* Issue an important message. HTUserMsg() * -------------------------------- */ void HTUserMsg(const char *Msg) { _statusline(Msg); if (non_empty(Msg)) { CTRACE((tfp, "User message: %s\n", Msg)); LYstore_message(Msg); #if !(defined(USE_SLANG) || defined(WIDEC_CURSES)) if (IS_CJK_TTY) { clearok(curscr, TRUE); LYrefresh(); } #endif LYSleepMsg(); } } void HTUserMsg2(const char *Msg2, const char *Arg) { _user_message(Msg2, Arg); if (non_empty(Msg2)) { CTRACE((tfp, "User message: ")); CTRACE((tfp, Msg2, Arg)); CTRACE((tfp, "\n")); LYstore_message2(Msg2, Arg); LYSleepMsg(); } } /* Issue a progress message. HTProgress() * ------------------------- */ void HTProgress(const char *Msg) { statusline(Msg); LYstore_message(Msg); CTRACE((tfp, "%s\n", Msg)); LYSleepDelay(); } const char *HTProgressUnits(int rate) { static const char *bunits = 0; static const char *kbunits = 0; if (!bunits) { bunits = gettext("bytes"); kbunits = gettext(LYTransferName); } return ((rate == rateKB) #ifdef USE_READPROGRESS || (rate == rateEtaKB) || (rate == rateEtaKB2) #endif )? kbunits : bunits; } static const char *sprint_bytes(char *s, off_t n, const char *was_units) { static off_t kb_units = 1024; const char *u = HTProgressUnits(LYTransferRate); if (isRateInKB(LYTransferRate)) { if (n >= 10 * kb_units) { sprintf(s, "%" PRI_off_t, CAST_off_t (n / kb_units)); } else if (n > 999) { /* Avoid switching between 1016b/s and 1K/s */ sprintf(s, "%.2g", ((double) n) / (double) kb_units); } else { sprintf(s, "%" PRI_off_t, CAST_off_t (n)); u = HTProgressUnits(rateBYTES); } } else { sprintf(s, "%" PRI_off_t, CAST_off_t (n)); } if (!was_units || was_units != u) sprintf(s + strlen(s), " %s", u); return u; } #ifdef USE_READPROGRESS #define TIME_HMS_LENGTH (36) static char *sprint_tbuf(char *s, long t) { const char *format = ((LYTransferRate == rateEtaBYTES2 || LYTransferRate == rateEtaKB2) ? "% 2ld%c" : "%ld%c"); char *base = s; if (t < 0) { strcpy(s, "forever"); } else { if (t > (3600 * 24)) { sprintf(s, format, t / (3600 * 24), 'd'); s += strlen(s); t %= (3600 * 24); } if (t > 3600) { sprintf(s, format, t / 3600, 'h'); s += strlen(s); t %= 3600; } if (t > 60) { sprintf(s, format, t / 60, 'm'); s += strlen(s); t %= 60; } if (s == base) { sprintf(s, "% 2ld sec", t); } else if (t != 0) { sprintf(s, format, t, 's'); } } return base; } #endif /* USE_READPROGRESS */ /* Issue a read-progress message. HTReadProgress() * ------------------------------ */ void HTReadProgress(off_t bytes, off_t total) { static off_t bytes_last, total_last; static off_t transfer_rate = 0; static char *line = NULL; char bytesp[80], totalp[80], transferp[80]; int renew = 0; const char *was_units; #ifdef HAVE_GETTIMEOFDAY struct timeval tv; double now; static double first, last, last_active; gettimeofday(&tv, (struct timezone *) 0); now = (double) tv.tv_sec + (double) tv.tv_usec / 1000000.; #else #if defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H) static double now, first, last, last_active; struct timeb tb; ftime(&tb); now = tb.time + (double) tb.millitm / 1000; #else time_t now = time((time_t *) 0); /* once per second */ static time_t first, last, last_active; #endif #endif if (!LYShowTransferRate) LYTransferRate = rateOFF; if (bytes == 0) { first = last = last_active = now; bytes_last = bytes; } else if (bytes < 0) { /* stalled */ bytes = bytes_last; total = total_last; } /* 1 sec delay for transfer_rate calculation without g-t-o-d */ if ((bytes > 0) && (now > first)) { if (transfer_rate <= 0) { /* the very first time */ transfer_rate = (off_t) ((double) (bytes) / (now - first)); /* bytes/sec */ } total_last = total; /* * Optimal refresh time: every 0.2 sec */ #if defined(HAVE_GETTIMEOFDAY) || (defined(HAVE_FTIME) && defined(HAVE_SYS_TIMEB_H)) if (now >= last + 0.2) renew = 1; #else /* * Use interpolation. (The transfer rate may be not constant * when we have partial content in a proxy. We adjust transfer_rate * once a second to minimize interpolation error below.) */ if ((now != last) || ((bytes - bytes_last) > (transfer_rate / 5))) { renew = 1; bytes_last += (transfer_rate / 5); /* until we got next second */ } #endif if (renew) { if (now > last) { last = now; if (bytes_last != bytes) last_active = now; bytes_last = bytes; transfer_rate = (off_t) ((double) bytes / (now - first)); /* more accurate value */ } if (total > 0) was_units = sprint_bytes(totalp, total, 0); else was_units = 0; sprint_bytes(bytesp, bytes, was_units); switch ((TransferRate) LYTransferRate) { #ifdef USE_PROGRESSBAR case rateBAR: /* * If we know the total size of the file, we can compute * a percentage, and show a corresponding progress bar. */ HTSprintf0(&line, gettext("Read %s of data"), bytesp); if (total > 0) { float percent = (float) bytes / (float) total; int meter = (int) (((float) LYcolLimit * percent) - 5); CTRACE((tfp, "rateBAR: bytes: %" PRI_off_t ", total: " "%" PRI_off_t "\n", CAST_off_t (bytes), CAST_off_t (total))); CTRACE((tfp, "meter = %d\n", meter)); HTSprintf0(&line, "%d%% ", (int) (percent * 100)); while (meter-- > 0) StrAllocCat(line, "I"); CTRACE((tfp, "%s\n", line)); CTRACE_FLUSH(tfp); } break; #endif default: if (total > 0) { HTSprintf0(&line, gettext("Read %s of %s of data"), bytesp, totalp); } else { HTSprintf0(&line, gettext("Read %s of data"), bytesp); } if (LYTransferRate != rateOFF && transfer_rate > 0) { sprint_bytes(transferp, transfer_rate, 0); HTSprintf(&line, gettext(", %s/sec"), transferp); } break; } #ifdef USE_READPROGRESS if (LYTransferRate == rateEtaBYTES || LYTransferRate == rateEtaKB || LYTransferRate == rateEtaBYTES2 || LYTransferRate == rateEtaKB2) { char tbuf[TIME_HMS_LENGTH]; if (now - last_active >= 5) HTSprintf(&line, gettext(" (stalled for %s)"), sprint_tbuf(tbuf, (long) (now - last_active))); if (total > 0 && transfer_rate) HTSprintf(&line, gettext(", ETA %s"), sprint_tbuf(tbuf, (long) ((total - bytes) / transfer_rate))); } #endif switch ((TransferRate) LYTransferRate) { #ifdef USE_PROGRESSBAR case rateBAR: /* * If we were not able to show a progress bar, just show * a "." for progress. */ if (total <= 0) StrAllocCat(line, "."); break; #endif default: StrAllocCat(line, "."); break; } if (total < -1) StrAllocCat(line, gettext(" (Press 'z' to abort)")); /* do not store the message for history page. */ statusline(line); CTRACE((tfp, "%s\n", line)); } } #ifdef LY_FIND_LEAKS FREE(line); #endif } static BOOL conf_cancelled = NO; /* used by HTConfirm only - kw */ BOOL HTLastConfirmCancelled(void) { if (conf_cancelled) { conf_cancelled = NO; /* reset */ return (YES); } else { return (NO); } } /* * Prompt for yes/no response, but let a configuration variable override * the prompt entirely. */ int HTForcedPrompt(int option, const char *msg, int dft) { int result = FALSE; const char *show = NULL; char *msg2 = NULL; if (option == FORCE_PROMPT_DFT) { result = HTConfirmDefault(msg, dft); } else { if (option == FORCE_PROMPT_YES) { show = gettext("yes"); result = YES; } else if (option == FORCE_PROMPT_NO) { show = gettext("no"); result = NO; } else { return HTConfirmDefault(msg, dft); /* bug... */ } HTSprintf(&msg2, "%s %s", msg, show); HTUserMsg(msg2); free(msg2); } return result; } #define DFT_CONFIRM ~(YES|NO) /* Seek confirmation with default answer. HTConfirmDefault() * -------------------------------------- */ int HTConfirmDefault(const char *Msg, int Dft) { /* Meta-note: don't move the following note from its place right in front of the first gettext(). As it is now, it should automatically appear in generated lynx.pot files. - kw */ /* NOTE TO TRANSLATORS: If you provide a translation for "yes", lynx * will take the first byte of the translation as a positive response * to Yes/No questions. If you provide a translation for "no", lynx * will take the first byte of the translation as a negative response * to Yes/No questions. For both, lynx will also try to show the * first byte in the prompt as a character, instead of (y) or (n), * respectively. This will not work right for multibyte charsets! * Don't translate "yes" and "no" for CJK character sets (or translate * them to "yes" and "no"). For a translation using UTF-8, don't * translate if the translation would begin with anything but a 7-bit * (US_ASCII) character. That also means do not translate if the * translation would begin with anything but a 7-bit character, if * you use a single-byte character encoding (a charset like ISO-8859-n) * but anticipate that the message catalog may be used re-encoded in * UTF-8 form. * For translations using other character sets, you may also wish to * leave "yes" and "no" untranslated, if using (y) and (n) is the * preferred behavior. * Lynx will also accept y Y n N as responses unless there is a conflict * with the first letter of the "yes" or "no" translation. */ const char *msg_yes = gettext("yes"); const char *msg_no = gettext("no"); int result = -1; /* If they're not really distinct in the first letter, revert to English */ if (TOUPPER(*msg_yes) == TOUPPER(*msg_no)) { msg_yes = "yes"; msg_no = "no"; } conf_cancelled = NO; if (dump_output_immediately) { /* Non-interactive, can't respond */ if (Dft == DFT_CONFIRM) { CTRACE((tfp, "Confirm: %s (%c/%c) ", Msg, *msg_yes, *msg_no)); } else { CTRACE((tfp, "Confirm: %s (%c) ", Msg, (Dft == YES) ? *msg_yes : *msg_no)); } CTRACE((tfp, "- NO, not interactive.\n")); result = NO; } else { char *msg = NULL; char fallback_y = 'y'; /* English letter response as fallback */ char fallback_n = 'n'; /* English letter response as fallback */ if (fallback_y == *msg_yes || fallback_y == *msg_no) fallback_y = '\0'; /* conflict or duplication, don't use */ if (fallback_n == *msg_yes || fallback_n == *msg_no) fallback_n = '\0'; /* conflict or duplication, don't use */ if (Dft == DFT_CONFIRM) HTSprintf0(&msg, "%s (%c/%c) ", Msg, *msg_yes, *msg_no); else HTSprintf0(&msg, "%s (%c) ", Msg, (Dft == YES) ? *msg_yes : *msg_no); if (LYTraceLogFP) { CTRACE((tfp, "Confirm: %s", msg)); } _statusline(msg); FREE(msg); while (result < 0) { int c = LYgetch_single(); #ifdef VMS if (HadVMSInterrupt) { HadVMSInterrupt = FALSE; c = TOUPPER(*msg_no); } #endif /* VMS */ if (c == TOUPPER(*msg_yes)) { result = YES; } else if (c == TOUPPER(*msg_no)) { result = NO; } else if (fallback_y && c == fallback_y) { result = YES; } else if (fallback_n && c == fallback_n) { r
#
#
#           The Nim Compiler
#        (c) Copyright 2012 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## This module contains the data structures for the semantic checking phase.

import
  strutils, lists, intsets, options, lexer, ast, astalgo, trees, treetab,
  wordrecg,
  ropes, msgs, platform, os, condsyms, idents, renderer, types, extccomp, math,
  magicsys, nversion, nimsets, parser, times, passes, rodread, vmdef

type
  TOptionEntry* = object of lists.TListEntry # entries to put on a
                                             # stack for pragma parsing
    options*: TOptions
    defaultCC*: TCallingConvention
    dynlib*: PLib
    notes*: TNoteKinds
    otherPragmas*: PNode      # every pragma can be pushed

  POptionEntry* = ref TOptionEntry
  PProcCon* = ref TProcCon
  TProcCon* = object          # procedure context; also used for top-level
                              # statements
    owner*: PSym              # the symbol this context belongs to
    resultSym*: PSym          # the result symbol (if we are in a proc)
    nestedLoopCounter*: int   # whether we are in a loop or not
    nestedBlockCounter*: int  # whether we are in a block or not
    inTryStmt*: int           # whether we are in a try statement; works also
                              # in standalone ``except`` and ``finally``
    next*: PProcCon           # used for stacking procedure contexts
    wasForwarded*: bool       # whether the current proc has a separate header
    bracketExpr*: PNode       # current bracket expression (for ^ support)

  TInstantiationPair* = object
    genericSym*: PSym
    inst*: PInstantiation

  TExprFlag* = enum
    efLValue, efWantIterator, efInTypeof,
    efWantStmt, efAllowStmt, efDetermineType,
    efAllowDestructor, efWantValue, efOperand, efNoSemCheck
  TExprFlags* = set[TExprFlag]

  TTypeAttachedOp* = enum
    attachedAsgn,
    attachedDeepCopy,
    attachedDestructor

  PContext* = ref TContext
  TContext* = object of TPassContext # a context represents a module
    module*: PSym              # the module sym belonging to the context
    currentScope*: PScope      # current scope
    importTable*: PScop