/* * File: prompt.cpp * This program is used to generate a bash prompt with rainbow colors. * It can also be used to generate the necessary environment variables * */ #include "common.hpp" #include "ip.hpp" #include "rainbow.hpp" int randint(int n) { if (n<=0) return 0; FILE *f = fopen("/dev/urandom", "r"); if (f == NULL) return 0; unsigned char buf; unsigned int ret = 0; for (int i = 0; i < 4; i++) { ret<<=8; fread(&buf, 1, 1, f); ret += buf; } //fread(&buf, 1, 4, f); fclose(f); ret = ret % n; return (int)ret; } str mouthlist = ")3>]DPO"; str eyelist = ";:="; str emote(){ return eyelist.substr(randint(eyelist.length()-1),1) + mouthlist.substr(randint(mouthlist.length()-1),1); } struct escape { str output = ""; str color(str color,bool background=false) { if (color.length()==0) return ""; if (color.length() <= 3)color="5;"+color; else color="2;"+color; if (background) return "48;" + color; return "38;" + color; } void add(str s, str fg="", str bg="", bool bold=false) { if (bold==1) s = wrap("1") + s; if (fg!="") s = wrap(color(fg)) + s; if (bg!="") s = wrap(color(bg,true)) + s; output += s + wrap("0"); } struct rainbow r; void rain(str s) { for (int i = 0; i < s.length(); i++) { add(s.substr(i,1), r.c.str()); r.next(); } } void set() { exportenv("PS1",output); } }; int wave(int x) {return (int)(3+3*(sin(x/1.4)));} rainbow rain(int wavefactor=6) { rainbow r; const char* rainenv = getenv("RAINBOW"); if (rainenv == NULL)r.init(35 - randint(10)); else { atoi(r.s, rainenv, atoi(r.c.b, rainenv, atoi(r.c.g, rainenv,atoi(r.c.r, rainenv, 0)+1)+1)+1); r.next(); } exportenv("RAINBOW", r.c.str()+";"+std::to_string(r.s)); for(int i = 0; i < abs(wave(wavefactor)); i++)r.next(); return r; } void getpwd(escape &esc) { str pwd, home; if (!strEnv(pwd, "PWD")) return; strEnv(home, "HOME"); int inHome = 0; if (!home.empty() && pwd.length() >= home.length() && pwd.substr(0, home.length()) == home) { pwd = pwd.substr(home.length()); inHome = 1; } std::vector parts = split(pwd, '/'); int n = 2; int siz = parts.size(); intenv(n, "PWDLEN"); pwd=".."; if (n <= 0 || n >= siz) { n = 0; if (inHome) pwd="~"; else pwd="/"; } else n = siz - n; for (esc.rain(" "+pwd); n < siz; n++) { esc.rain(" "+parts[n]); } esc.output += " "; } void checkBash() { str env; if (!strEnv(env, "SHELL")) { exit(1); } int l = env.length(); if (l < 4 || env.substr(l - 4, 4) != "bash") { exit(1); } } int validPart(char &part) { const str parts = "i?uhlde"; for (int i = 0; i < parts.length(); i++) { if (part == parts[i]) return 1; } return 0; } // return 1 on success, 0 on failure int parseFmtPart(str &fmt, int &i, char &part, str &fg, str &bg) { if (i >= fmt.length() || fmt[i] != '%') return 0; fg = ""; bg = ""; int v = 0; str *col = &fg; for (i++; i < fmt.length(); i++) { part = fmt[i]; if (part == '.') { if (col == &bg) return 0; // only one dot allowed v = 0; col = &bg; continue; } if (part >= '0' && part <= '9') { *col += part; v = v * 10 + (int)(part - '0'); if (v > 255) return 0; // color out of range continue; } return validPart(part); } return 0; } int doIP = 0; void addIP(escape &esc) { if (!doIP) return; IP ip; if (ip.get()) esc.output+=ip.toColor()+" "; } int lineno ; void addPart(escape &esc, char &part, str &fg, str &bg) { str s; switch (part) { case 'i': addIP(esc); return; case 'd': getpwd(esc); return; case '?': if (fg == "" && bg == "") fg = "202"; s = "\\${?}"; break; case 'u': s = envorcmd("USER", "whoami"); break; case 'h': s = envorcmd("HOSTNAME", "hostname"); break; case 'l': s = std::to_string(lineno); break; case 'e': s = emote(); break; default: return; } if (fg == "" && bg == "") esc.rain(s); else esc.add(s, fg, bg); esc.output += " "; } str getFMT() { const char* ipcol = getenv("IPCOLOR"); if (ipcol == NULL || !(std::string(ipcol)=="none"||std::string(ipcol)=="NONE")) doIP = 1; const char* fmtt = getenv("RBPSFMT"); if (fmtt == NULL) { if (doIP) return "%i%?%u%l%e%d"; return "%?%u%h%l%e%d"; } return std::string(fmtt); } int main(int argc,char** argv) { checkBash(); escape PS1; for (int i=1;i