📄 marshal.c
字号:
if(out + 4 >= e) goto exhausted; *out++ = t64e[(b24>>18)]; *out++ = t64e[(b24>>12)&0x3f]; *out++ = '='; break; case 0: if((i%18) != 0) *out++ = '\n'; *out = 0; return out - start; }exhausted: *out++ = '='; *out++ = '\n'; *out = 0; return out - start;}voidfreealias(Alias *a){ freeaddrs(a->addr); free(a);}voidfreealiases(Alias *a){ Alias *next; while(a != nil){ next = a->next; freealias(a); a = next; }}//// read alias file//Alias*readaliases(void){ Alias *a, **l, *first; Addr *addr, **al; String *file, *line, *token; static int already; Sinstack *sp; first = nil; file = s_new(); line = s_new(); token = s_new(); // open and get length mboxpath("names", login, file, 0); sp = s_allocinstack(s_to_c(file)); if(sp == nil) goto out; l = &first; // read a line at a time. while(s_rdinstack(sp, s_restart(line))!=nil) { s_restart(line); a = emalloc(sizeof(Alias)); al = &a->addr; for(;;){ if(s_parse(line, s_restart(token))==0) break; addr = emalloc(sizeof(Addr)); addr->v = strdup(s_to_c(token)); addr->next = 0; *al = addr; al = &addr->next; } if(a->addr == nil || a->addr->next == nil){ freealias(a); continue; } a->next = nil; *l = a; l = &a->next; } s_freeinstack(sp);out: s_free(file); s_free(line); s_free(token); return first;}Addr*newaddr(char *name){ Addr *a; a = emalloc(sizeof(*a)); a->next = nil; a->v = estrdup(name); if(a->v == nil) sysfatal("%r"); return a;}//// expand personal aliases since the names are meaningless in// other contexts//Addr*_expand(Addr *old, int *changedp){ Alias *al; Addr *first, *next, **l, *a; *changedp = 0; first = nil; l = &first; for(;old != nil; old = next){ next = old->next; for(al = aliases; al != nil; al = al->next){ if(strcmp(al->addr->v, old->v) == 0){ for(a = al->addr->next; a != nil; a = a->next){ *l = newaddr(a->v); if(*l == nil) sysfatal("%r"); l = &(*l)->next; *changedp = 1; } break; } } if(al != nil){ freeaddr(old); continue; } *l = old; old->next = nil; l = &(*l)->next; } return first;}Addr*rexpand(Addr *old){ int i, changed; changed = 0; for(i=0; i<32; i++){ old = _expand(old, &changed); if(changed == 0) break; } return old;}Addr*unique(Addr *first){ Addr *a, **l, *x; for(a = first; a != nil; a = a->next){ for(l = &a->next; *l != nil;){ if(strcmp(a->v, (*l)->v) == 0){ x = *l; *l = x->next; freeaddr(x); } else l = &(*l)->next; } } return first;}Addr*expand(int ac, char **av){ Addr *first, **l; int i; first = nil; // make a list of the starting addresses l = &first; for(i = 0; i < ac; i++){ *l = newaddr(av[i]); if(*l == nil) sysfatal("%r"); l = &(*l)->next; } // recurse till we don't change any more return unique(rexpand(first));}Addr*concataddr(Addr *a, Addr *b){ Addr *oa; if(a == nil) return b; oa = a; for(; a->next; a=a->next) ; a->next = b; return oa;}voidfreeaddr(Addr *ap){ free(ap->v); free(ap);}voidfreeaddrs(Addr *ap){ Addr *next; for(; ap; ap=next) { next = ap->next; freeaddr(ap); }}String*s_copyn(char *s, int n){ return s_nappend(s_reset(nil), s, n);}// fetch the next token from an RFC822 address string// we assume the header is RFC822-conformant in that// we recognize escaping anywhere even though it is only// supposed to be in quoted-strings, domain-literals, and comments.//// i'd use yylex or yyparse here, but we need to preserve // things like comments, which i think it tosses away.//// we're not strictly RFC822 compliant. we misparse such nonsense as//// To: gre @ (Grace) plan9 . (Emlin) bell-labs.com//// make sure there's no whitespace in your addresses and // you'll be fine.//enum { Twhite, Tcomment, Twords, Tcomma, Tleftangle, Trightangle, Terror, Tend,};//char *ty82[] = {"white", "comment", "words", "comma", "<", ">", "err", "end"};#define ISWHITE(p) ((p)==' ' || (p)=='\t' || (p)=='\n' || (p)=='\r')intget822token(String **tok, char *p, char **pp){ char *op; int type; int quoting; op = p; switch(*p){ case '\0': *tok = nil; *pp = nil; return Tend; case ' ': // get whitespace case '\t': case '\n': case '\r': type = Twhite; while(ISWHITE(*p)) p++; break; case '(': // get comment type = Tcomment; for(p++; *p && *p != ')'; p++) if(*p == '\\') { if(*(p+1) == '\0') { *tok = nil; return Terror; } p++; } if(*p != ')') { *tok = nil; return Terror; } p++; break; case ',': type = Tcomma; p++; break; case '<': type = Tleftangle; p++; break; case '>': type = Trightangle; p++; break; default: // bunch of letters, perhaps quoted strings tossed in type = Twords; quoting = 0; for(; *p && (quoting || (!ISWHITE(*p) && *p != '>' && *p != '<' && *p != ',')); p++) { if(*p == '"') quoting = !quoting; if(*p == '\\') { if(*(p+1) == '\0') { *tok = nil; return Terror; } p++; } } break; } if(pp) *pp = p; *tok = s_copyn(op, p-op); return type;} // expand local aliases in an RFC822 mail line// add list of expanded addresses to to.Addr*expandline(String **s, Addr *to){ Addr *na, *nto, *ap; char *p; int tok, inangle, hadangle, nword; String *os, *ns, *stok, *lastword, *sinceword; os = s_copy(s_to_c(*s)); p = strchr(s_to_c(*s), ':'); assert(p != nil); p++; ns = s_copyn(s_to_c(*s), p-s_to_c(*s)); stok = nil; nto = nil; // // the only valid mailbox namings are word // and word* < addr > // without comments this would be simple. // we keep the following: // lastword - current guess at the address // sinceword - whitespace and comment seen since lastword // lastword = s_new(); sinceword = s_new(); inangle = 0; nword = 0; hadangle = 0; for(;;) { stok = nil; switch(tok = get822token(&stok, p, &p)){ default: abort(); case Tcomma: case Tend: if(inangle) goto Error; if(nword != 1) goto Error; na = rexpand(newaddr(s_to_c(lastword))); s_append(ns, na->v); s_append(ns, s_to_c(sinceword)); for(ap=na->next; ap; ap=ap->next) { s_append(ns, ", "); s_append(ns, ap->v); } nto = concataddr(na, nto); if(tok == Tcomma){ s_append(ns, ","); s_free(stok); } if(tok == Tend) goto Break2; inangle = 0; nword = 0; hadangle = 0; s_reset(sinceword); s_reset(lastword); break; case Twhite: case Tcomment: s_append(sinceword, s_to_c(stok)); s_free(stok); break; case Trightangle: if(!inangle) goto Error; inangle = 0; hadangle = 1; s_append(sinceword, s_to_c(stok)); s_free(stok); break; case Twords: case Tleftangle: if(hadangle) goto Error; if(tok != Tleftangle && inangle && s_len(lastword)) goto Error; if(tok == Tleftangle) { inangle = 1; nword = 1; } s_append(ns, s_to_c(lastword)); s_append(ns, s_to_c(sinceword)); s_reset(sinceword); if(tok == Tleftangle) { s_append(ns, "<"); s_reset(lastword); } else { s_free(lastword); lastword = stok; } if(!inangle) nword++; break; case Terror: // give up, use old string, addrs Error: ns = os; os = nil; freeaddrs(nto); nto = nil; werrstr("rfc822 syntax error"); rfc822syntaxerror = 1; goto Break2; } }Break2: s_free(*s); s_free(os); *s = ns; nto = concataddr(nto, to); return nto;}voidBdrain(Biobuf *b){ char buf[8192]; while(Bread(b, buf, sizeof buf) > 0) ;}voidreadmimetypes(void){ Biobuf *b; char *p; char *f[6]; char type[256]; static int alloced, inuse; if(mimetypes == 0){ alloced = 256; mimetypes = emalloc(alloced*sizeof(Ctype)); mimetypes[0].ext = ""; } b = Bopen("/sys/lib/mimetype", OREAD); if(b == nil) return; for(;;){ p = Brdline(b, '\n'); if(p == nil) break; p[Blinelen(b)-1] = 0; if(tokenize(p, f, 6) < 4) continue; if(strcmp(f[0], "-") == 0 || strcmp(f[1], "-") == 0 || strcmp(f[2], "-") == 0) continue; if(inuse + 1 >= alloced){ alloced += 256; mimetypes = erealloc(mimetypes, alloced*sizeof(Ctype)); } snprint(type, sizeof(type), "%s/%s", f[1], f[2]); mimetypes[inuse].type = estrdup(type); mimetypes[inuse].ext = estrdup(f[0]+1); mimetypes[inuse].display = !strcmp(type, "text/plain"); inuse++; // always make sure there's a terminator mimetypes[inuse].ext = 0; } Bterm(b);}char*estrdup(char *x){ x = strdup(x); if(x == nil) fatal("memory"); return x;}void*emalloc(int n){ void *x; x = malloc(n); if(x == nil) fatal("%r"); return x;}void*erealloc(void *x, int n){ x = realloc(x, n); if(x == nil) fatal("%r"); return x;}//// Formatter for %"// Use double quotes to protect white space, frogs, \ and "//enum{ Qok = 0, Qquote, Qbackslash,};static intneedtoquote(Rune r){ if(r >= Runeself) return Qquote; if(r <= ' ') return Qquote; if(r=='\\' || r=='"') return Qbackslash; return Qok;}intdoublequote(Fmt *f){ char *s, *t; int w, quotes; Rune r; s = va_arg(f->args, char*); if(s == nil || *s == '\0') return fmtstrcpy(f, "\"\""); quotes = 0; for(t=s; *t; t+=w){ w = chartorune(&r, t); quotes |= needtoquote(r); } if(quotes == 0) return fmtstrcpy(f, s); fmtrune(f, '"'); for(t=s; *t; t+=w){ w = chartorune(&r, t); if(needtoquote(r) == Qbackslash) fmtrune(f, '\\'); fmtrune(f, r); } return fmtrune(f, '"');}intrfc2047fmt(Fmt *fmt){ char *s, *p; s = va_arg(fmt->args, char*); if(s == nil) return fmtstrcpy(fmt, ""); for(p=s; *p; p++) if((uchar)*p >= 0x80) goto hard; return fmtstrcpy(fmt, s);hard: fmtprint(fmt, "=?utf-8?q?"); for(p=s; *p; p++){ if(*p == ' ') fmtrune(fmt, '_'); else if(*p == '_' || *p == '\t' || *p == '=' || *p == '?' || (uchar)*p >= 0x80) fmtprint(fmt, "=%.2uX", (uchar)*p); else fmtrune(fmt, (uchar)*p); } fmtprint(fmt, "?="); return 0;}char*mksubject(char *line){ char *p, *q; static char buf[1024]; p = strchr(line, ':')+1; while(*p == ' ') p++; for(q=p; *q; q++) if((uchar)*q >= 0x80) goto hard; return line;hard: snprint(buf, sizeof buf, "Subject: %U", p); return buf;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -