astr variableDump(le *varlist) { astr as = astr_new(); for (; varlist; varlist = varlist->list_next) { if (varlist->branch) { astr_afmt(as, "%s \t", varlist->data); astr_cat_delete(as, leDumpReformat(varlist->branch)); astr_cat_char(as, '\n'); } } return as; }
/* * Convert a key code sequence into a key code sequence string. */ astr keyvectostr(size_t *keys, size_t numkeys) { size_t i; astr as = astr_new(); for (i = 0; i < numkeys; i++) { astr key = chordtostr(keys[i]); astr_cat(as, key); astr_delete(key); if (i < numkeys - 1) astr_cat_char(as, ' '); } return as; }
static void draw_status_line(size_t line, Window *wp) { size_t i; char *buf, *eol_type; Point pt = window_pt(wp); astr as, bs; term_attrset(1, FONT_REVERSE); term_move(line, 0); for (i = 0; i < wp->ewidth; ++i) term_addch('-'); if (cur_bp->eol == coding_eol_cr) eol_type = "(Mac)"; else if (cur_bp->eol == coding_eol_crlf) eol_type = "(DOS)"; else eol_type = ":"; term_move(line, 0); bs = astr_afmt(astr_new(), "(%d,%d)", pt.n+1, get_goalc_wp(wp)); as = astr_afmt(astr_new(), "--%s%2s %-15s %s %-9s (Text", eol_type, make_mode_line_flags(wp), wp->bp->name, make_screen_pos(wp, &buf), astr_cstr(bs)); free(buf); astr_delete(bs); if (wp->bp->flags & BFLAG_AUTOFILL) astr_cat_cstr(as, " Fill"); if (wp->bp->flags & BFLAG_OVERWRITE) astr_cat_cstr(as, " Ovwrt"); if (thisflag & FLAG_DEFINING_MACRO) astr_cat_cstr(as, " Def"); if (wp->bp->flags & BFLAG_ISEARCH) astr_cat_cstr(as, " Isearch"); astr_cat_char(as, ')'); term_addnstr(astr_cstr(as), min(term_width(), astr_len(as))); astr_delete(as); term_attrset(1, FONT_NORMAL); }
/* * Return the current directory. */ static astr get_current_dir(void) { astr buf; int p; if (cur_bp->filename != NULL) /* If the current buffer has a filename, get the current directory name from it. */ buf = astr_new_cstr(cur_bp->filename); else { /* Get the current directory name from the system. */ buf = agetcwd(); if (astr_len(buf) != 0 && *astr_char(buf, -1) != '/') astr_cat_char(buf, '/'); } p = astr_rfind_cstr(buf, "/"); astr_truncate(buf, p + 1); return buf; }
/* * Convert a key like "\\C-xrs" to "C-x r s" */ astr simplify_key(char *key) { int i, j; size_t *keys; astr dest = astr_new(); if (key == NULL) return dest; i = keystrtovec(key, &keys); for (j = 0; j < i; j++) { astr as; if (j > 0) astr_cat_char(dest, ' '); as = chordtostr(keys[j]); astr_cat(dest, as); astr_delete(as); } if (i > 0) free(keys); return dest; }
static void draw_status_line (size_t line, Window wp) { term_attrset (FONT_REVERSE); term_move (line, 0); for (size_t i = 0; i < get_window_ewidth (wp); ++i) term_addstr ("-"); const char *eol_type; if (get_buffer_eol (cur_bp) == coding_eol_cr) eol_type = "(Mac)"; else if (get_buffer_eol (cur_bp) == coding_eol_crlf) eol_type = "(DOS)"; else eol_type = ":"; term_move (line, 0); size_t n = offset_to_line (get_window_bp (wp), window_o (wp)); astr as = astr_fmt ("--%s%2s %-15s %s %-9s (Fundamental", eol_type, make_mode_line_flags (wp), get_buffer_name (get_window_bp (wp)), make_screen_pos (wp), astr_cstr (astr_fmt ("(%zu,%zu)", n + 1, get_goalc_bp (get_window_bp (wp), window_o (wp))))); if (get_buffer_autofill (get_window_bp (wp))) astr_cat_cstr (as, " Fill"); if (thisflag & FLAG_DEFINING_MACRO) astr_cat_cstr (as, " Def"); if (get_buffer_isearch (get_window_bp (wp))) astr_cat_cstr (as, " Isearch"); astr_cat_char (as, ')'); term_addstr (astr_cstr (as)); term_attrset (FONT_NORMAL); }
/* * This functions does some corrections and expansions to * the passed path: * * - expands `~/' and `~name/' expressions; * - replaces `//' with `/' (restarting from the root directory); * - removes `..' and `.' entries. * * The return value indicates success or failure. */ bool expand_path (astr path) { int ok = true; const char *sp = astr_cstr (path); astr epath = astr_new (); if (*sp != '/' && *sp != '~') { astr_cat (epath, agetcwd ()); if (astr_len (epath) == 0 || astr_get (epath, astr_len (epath) - 1) != '/') astr_cat_char (epath, '/'); } for (const char *p = sp; *p != '\0';) { if (*p == '/') { if (*++p == '/') { /* Got `//'. Restart from this point. */ while (*p == '/') p++; astr_truncate (epath, 0); } if (astr_len (epath) == 0 || astr_get (epath, astr_len (epath) - 1) != '/') astr_cat_char (epath, '/'); } else if (*p == '~' && (p == sp || p[-1] == '/')) { /* Got `/~' or leading `~'. Restart from this point. */ struct passwd *pw; astr_truncate (epath, 0); ++p; if (*p == '/') { /* Got `~/'. Insert the user's home directory. */ pw = getpwuid (getuid ()); if (pw == NULL) { ok = false; break; } if (!STREQ (pw->pw_dir, "/")) astr_cat_cstr (epath, pw->pw_dir); } else { /* Got `~something'. Insert that user's home directory. */ astr as = astr_new (); while (*p != '\0' && *p != '/') astr_cat_char (as, *p++); pw = getpwnam (astr_cstr (as)); if (pw == NULL) { ok = false; break; } astr_cat_cstr (epath, pw->pw_dir); } } else if (*p == '.' && (p[1] == '/' || p[1] == '\0')) { /* Got `.'. */ ++p; } else if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) { /* Got `..'. */ if (astr_len (epath) >= 1 && astr_get (epath, astr_len (epath) - 1) == '/') astr_truncate (epath, astr_len (epath) - 1); while (astr_get (epath, astr_len (epath) - 1) != '/' && astr_len (epath) >= 1) astr_truncate (epath, astr_len (epath) - 1); p += 2; } if (*p != '~') while (*p != '\0' && *p != '/') astr_cat_char (epath, *p++); } astr_cpy (path, epath); return ok; }
/* * Convert a key chord into its ASCII representation */ astr chordtostr(size_t key) { astr as = astr_new(); if (key & KBD_CTRL) astr_cat_cstr(as, "C-"); if (key & KBD_META) astr_cat_cstr(as, "M-"); key &= ~(KBD_CTRL | KBD_META); switch (key) { case KBD_PGUP: astr_cat_cstr(as, "<prior>"); break; case KBD_PGDN: astr_cat_cstr(as, "<next>"); break; case KBD_HOME: astr_cat_cstr(as, "<home>"); break; case KBD_END: astr_cat_cstr(as, "<end>"); break; case KBD_DEL: astr_cat_cstr(as, "<delete>"); break; case KBD_BS: astr_cat_cstr(as, "<backspace>"); break; case KBD_INS: astr_cat_cstr(as, "<insert>"); break; case KBD_LEFT: astr_cat_cstr(as, "<left>"); break; case KBD_RIGHT: astr_cat_cstr(as, "<right>"); break; case KBD_UP: astr_cat_cstr(as, "<up>"); break; case KBD_DOWN: astr_cat_cstr(as, "<down>"); break; case KBD_RET: astr_cat_cstr(as, "<RET>"); break; case KBD_TAB: astr_cat_cstr(as, "<TAB>"); break; case KBD_F1: astr_cat_cstr(as, "<f1>"); break; case KBD_F2: astr_cat_cstr(as, "<f2>"); break; case KBD_F3: astr_cat_cstr(as, "<f3>"); break; case KBD_F4: astr_cat_cstr(as, "<f4>"); break; case KBD_F5: astr_cat_cstr(as, "<f5>"); break; case KBD_F6: astr_cat_cstr(as, "<f6>"); break; case KBD_F7: astr_cat_cstr(as, "<f7>"); break; case KBD_F8: astr_cat_cstr(as, "<f8>"); break; case KBD_F9: astr_cat_cstr(as, "<f9>"); break; case KBD_F10: astr_cat_cstr(as, "<f10>"); break; case KBD_F11: astr_cat_cstr(as, "<f11>"); break; case KBD_F12: astr_cat_cstr(as, "<f12>"); break; case ' ': astr_cat_cstr(as, "SPC"); break; default: if (isgraph(key)) astr_cat_char(as, (int)(key & 0xff)); else astr_afmt(as, "<%x>", key); } return as; }
/* * Read the file contents into a buffer. * Return quietly if the file doesn't exist, or other error. */ void read_from_disk(const char *filename) { Line *lp; FILE *fp; int i, size, first_eol = TRUE; char *this_eol_type; size_t eol_len = 0, total_eols = 0; char buf[BUFSIZ]; if ((fp = fopen(filename, "r")) == NULL) { if (errno != ENOENT) { minibuf_write("%s: %s", filename, strerror(errno)); cur_bp->flags |= BFLAG_READONLY; } return; } #if HAVE_UNISTD_H if (!check_writable(filename)) cur_bp->flags |= BFLAG_READONLY; #endif lp = cur_bp->pt.p; /* Read first chunk and determine EOL type. */ if ((size = fread(buf, 1, BUFSIZ, fp)) > 0) { for (i = 0; i < size && total_eols < MAX_EOL_CHECK_COUNT; i++) { if (buf[i] == '\n' || buf[i] == '\r') { total_eols++; if (buf[i] == '\n') this_eol_type = coding_eol_lf; else if (i >= size || buf[i + 1] != '\n') this_eol_type = coding_eol_cr; else { this_eol_type = coding_eol_crlf; i++; } if (first_eol) { /* This is the first end-of-line. */ cur_bp->eol = this_eol_type; first_eol = FALSE; } else if (cur_bp->eol != this_eol_type) { /* This EOL is different from the last; arbitrarily choose LF. */ cur_bp->eol = coding_eol_lf; break; } } } /* Process this and subsequent chunks into lines. */ eol_len = strlen(cur_bp->eol); do { for (i = 0; i < size; i++) { if (strncmp(cur_bp->eol, buf + i, eol_len) != 0) astr_cat_char(lp->item, buf[i]); else { lp = list_prepend(lp, astr_new()); ++cur_bp->num_lines; i += eol_len - 1; } } } while ((size = fread(buf, 1, BUFSIZ, fp)) > 0); } list_next(lp) = cur_bp->lines; list_prev(cur_bp->lines) = lp; cur_bp->pt.p = list_next(cur_bp->lines); fclose(fp); }
/* * This functions does some corrections and expansions to * the passed path: * - expands `~/' and `~name/' expressions; * - replaces `//' with `/' (restarting from the root directory); * - removes `..' and `.' entries. * * If something goes wrong, the string is deleted and NULL returned */ astr expand_path(astr path) { int ret = TRUE; struct passwd *pw; const char *sp = astr_cstr(path); astr epath = astr_new(); if (*sp != '/') { astr_cat_delete(epath, agetcwd()); if (astr_len(epath) == 0 || *astr_char(epath, -1) != '/') astr_cat_char(epath, '/'); } while (*sp != '\0') { if (*sp == '/') { if (*++sp == '/') { /* Got `//'. Restart from this point. */ while (*sp == '/') sp++; astr_truncate(epath, 0); } astr_cat_char(epath, '/'); } else if (*sp == '~') { if (*(sp + 1) == '/') { /* Got `~/'. Restart from this point and insert the user's home directory. */ astr_truncate(epath, 0); if ((pw = getpwuid(getuid())) == NULL) { ret = FALSE; break; } if (strcmp(pw->pw_dir, "/") != 0) astr_cat_cstr(epath, pw->pw_dir); ++sp; } else { /* Got `~something'. Restart from this point and insert that user's home directory. */ astr as = astr_new(); astr_truncate(epath, 0); ++sp; while (*sp != '\0' && *sp != '/') astr_cat_char(as, *sp++); pw = getpwnam(astr_cstr(as)); astr_delete(as); if (pw == NULL) { ret = FALSE; break; } astr_cat_cstr(epath, pw->pw_dir); } } else if (*sp == '.') { if (*(sp + 1) == '/' || *(sp + 1) == '\0') { ++sp; if (*sp == '/' && *(sp + 1) != '/') ++sp; } else if (*(sp + 1) == '.' && (*(sp + 2) == '/' || *(sp + 2) == '\0')) { if (astr_len(epath) >= 1 && *astr_char(epath, -1) == '/') astr_truncate(epath, -1); while (*astr_char(epath, -1) != '/' && astr_len(epath) >= 1) astr_truncate(epath, -1); sp += 2; if (*sp == '/' && *(sp + 1) != '/') ++sp; } else goto got_component; } else { const char *p; got_component: p = sp; while (*p != '\0' && *p != '/') p++; if (*p == '\0') { /* Final filename */ astr_cat_cstr(epath, sp); break; } else { /* Non-final directory */ while (*sp != '/') astr_cat_char(epath, *sp++); } } } astr_cpy(path, epath); astr_delete(epath); if (!ret) { astr_delete(path); return NULL; } return path; }
static astr snagAToken(getcCallback getachar, ungetcCallback ungetachar, enum tokenname *tokenid) { int c; int doublequotes = 0; astr tok = astr_new(); *tokenid = T_EOF; /* Chew space to next token */ do { c = getachar(); /* Munch comments */ if (c == ';') do { c = getachar(); } while (c != EOF && c != '\n'); } while (c != EOF && (c == ' ' || c == '\t')); /* Snag token */ if (c == '(') { *tokenid = T_OPENPAREN; return tok; } else if (c == ')') { *tokenid = T_CLOSEPAREN; return tok; } else if (c == '\'') { *tokenid = T_QUOTE; return tok; } else if (c == '\n') { *tokenid = T_NEWLINE; return tok; } else if (c == EOF) { *tokenid = T_EOF; return tok; } /* It looks like a string. Snag to the next whitespace. */ if (c == '\"') { doublequotes = 1; c = getachar(); } while (1) { astr_cat_char(tok, (char)c); if (!doublequotes) { if (c == ')' || c == '(' || c == ';' || c == ' ' || c == '\n' || c == '\r' || c == EOF) { ungetachar(c); astr_truncate(tok, (ptrdiff_t)-1); if (!astr_cmp_cstr(tok, "quote")) { *tokenid = T_QUOTE; return tok; } *tokenid = T_WORD; return tok; } } else { switch (c) { case '\n': case '\r': case EOF: ungetachar(c); /* Fall through */ case '\"': astr_truncate(tok, (ptrdiff_t)-1); *tokenid = T_WORD; return tok; } } c = getachar(); } return tok; }