import "tcshDefine" // // This module provides for translation from synsh to tcsh. // //-------------------------------- Syntax support ------------------------------- // // Ok, this is kind of obscure/gross. // // The problem is side-effects of cond need to // be generated at the right time... and synmacs // just aren't that smart. // macro void if_(bool cond) code:if %(cond) then;; macro void if_(int cond) if(bool(%(cond))); synmac if { if_(%(cond)); code:INDENT;; %(do); code:OUTDENT;; code:else;; code:INDENT;; %(else); code:OUTDENT;; code:endif;; }; macro void while_(bool cond) code:while %(cond);; macro void while_(int cond) while(bool(%(cond))); synmac while { while_(%(cond)); code:INDENT;; %(do); code:OUTDENT;; code:end;; }; synmac for { %(init); while %(cond) do { %(body); %(cont); }; }; synmac add add(%(left),%(right)); synmac sub sub(%(left),%(right)); synmac mul mul(%(left),%(right)); synmac div div(%(left),%(right)); synmac rem rem(%(left),%(right)); synmac lt lt(%(left),%(right)); synmac gt gt(%(left),%(right)); synmac le le(%(left),%(right)); synmac ge ge(%(left),%(right)); synmac eq eq(%(left),%(right)); synmac ne ne(%(left),%(right)); synmac lor lor(%(left),%(right)); synmac land land(%(left),%(right)); synmac lnot lnot(%(val)); synmac index index (%(left),%(right)); synmac assign assign(%(left),%(right)); //--------------------------------- Ops on Integers --------------------------- macro int new(int x) { src:${%};; dst:%;; }; macro int assign(int a, int b) { code:set %[a]=%(b);; src:%(a);; dst:%[a];; }; macro bool lt(int a, int b) src:( %(a) < %(b) );; macro bool le(int a, int b) src:( %(a) <= %(b) );; macro bool gt(int a, int b) src:( %(a) > %(b) );; macro bool ge(int a, int b) src:( %(a) >= %(b) );; macro bool eq(int a, int b) src:( %(a) == %(b) );; macro bool ne(int a, int b) src:( %(a) != %(b) );; macro int add(int a, int b) { code:@ % = %(a) + %(b);; src:${%};; }; macro int sub(int a, int b) { code:@ % = %(a) - %(b);; src:${%};; }; macro int mul(int a, int b) { code:@ % = %(a) * %(b);; src:${%};; }; macro int div(int a, int b) { code:@ % = %(a) / %(b);; src:${%};; }; macro int rem(int a, int b) { code:@ % = %(a) %% %(b);; src:${%};; }; macro int inc(int a) %(a)+1; macro int dec(int a) %(a)-1; macro void print(int a) code:echo -n %(a);; macro void println(int a) code:echo %(a);; //--------------------------------- Ops on Strings --------------------------- macro string new(string x) { src:"$%";; dst:%;; }; macro string assign(string a, string b) { code:set %[a]=%(b);; src:%(a);; dst:%[a];; }; macro int assign(int a, string b) { code:set %[a]=%(b);; src:%(a);; dst:%[a];; }; macro bool lt(string a, string b) src:( %(a) < %(b) );; macro bool le(string a, string b) src:( %(a) <= %(b) );; macro bool gt(string a, string b) src:( %(a) > %(b) );; macro bool ge(string a, string b) src:( %(a) >= %(b) );; macro bool eq(string a, string b) src:( %(a) == %(b) );; macro bool ne(string a, string b) src:( %(a) != %(b) );; macro string add(string a, string b) { code:set %=%(a)%(b);; src:"$%";; }; macro string add(string a, int b) { code:set %=%(a)%(b);; src:"$%";; }; macro string add(int a, string b) { code:set %=%(a)%(b);; src:"$%";; }; macro void print(string a) code:echo -n %(a);; macro void println(string a) code:echo %(a);; //---------------------------------- Ops on Arrays of Strings ---------------------- // Note all arrays use the naked variable name as their 'src': macro stringList new(stringList x) { src:%;; dst:%;; }; macro stringList assign(stringList a, stringList b) { code:set %[a]=($%(b):q);; src:%(a);; dst:%[a];; }; macro int size(stringList l) src:${#%(l)};; macro string index_(stringList l, int i) src:"$%(l)[%(i)]";; macro string index (stringList l, int i) index_(%(l), %(i)+1); //--------------------------------- Ops on Bools --------------------------- macro bool land(bool a, bool b) src:( %(a) && %(b) );; macro bool lor (bool a, bool b) src:( %(a) || %(b) );; macro bool lnot(bool a) src:( ! %(a) );; macro void print(bool a) if %(a) then print("TRUE") else print("FALSE"); macro void println(bool a) if %(a) then println("TRUE") else println("FALSE"); // Casting ints to and from Bools: macro bool bool(int i) src:( %(i) );; macro int int(bool b) { code:if %(b) then;; code: set %=1;; code:else;; code: set %=0;; code:endif;; src:${%};; }; //----------------------- Ops on Times and Durations --------------------------- // We'll just represent time by seconds since 1970, // And durations in seconds, // Which means we can trivially convert them to and from int: macro duration new(duration x) { src:${%};; dst:%;; }; macro duration assign(duration a, duration b) { code:set %[a]=%(b);; src:%(a);; dst:%[a];; }; macro time new(time x) { src:${%};; dst:%;; }; macro time assign(time a, time b) { code:set %[a]=%(b);; src:%(a);; dst:%[a];; }; macro int int(time a) src:%(a);; macro time time(int a) src:%(a);; macro int int(duration a) src:%(a);; macro duration duration(int a) src:%(a);; // Creating dates: macro time now() { code:set %=`date +%%s`;; src:${%};; }; macro time yesterday() now()-hours(24); // Creating durations: macro duration seconds(int s) duration(%(s)); macro duration minutes(int s) seconds(%(s)*60); macro duration hours (int s) minutes(%(s)*60); macro duration days (int s) hours(%(s)*24); macro duration years (int s) days(%(s)*365); // Only approximate... // Comparisons are just based on their int equivalents: macro bool lt(time a, time b) int(%(a))< int(%(b)); macro bool le(time a, time b) int(%(a))<=int(%(b)); macro bool gt(time a, time b) int(%(a))> int(%(b)); macro bool ge(time a, time b) int(%(a))>=int(%(b)); macro bool eq(time a, time b) int(%(a))==int(%(b)); macro bool ne(time a, time b) int(%(a))!=int(%(b)); macro bool lt(duration a, duration b) int(%(a))< int(%(b)); macro bool le(duration a, duration b) int(%(a))<=int(%(b)); macro bool gt(duration a, duration b) int(%(a))> int(%(b)); macro bool ge(duration a, duration b) int(%(a))>=int(%(b)); macro bool eq(duration a, duration b) int(%(a))==int(%(b)); macro bool ne(duration a, duration b) int(%(a))!=int(%(b)); // Type shenanegans with duration arithmetic: macro duration add(duration a, duration b) duration(int(%(a)) + int(%(b))); macro duration sub(duration a, duration b) duration(int(%(a)) - int(%(b))); macro duration mul(int a, duration b) duration( %(a) * int(%(b))); macro duration mul(duration a, int b) duration(int(%(a)) * %(b) ); macro duration div(duration a, int b) duration(int(%(a)) / %(b) ); macro int div(duration a, duration b) int(%(a)) / int(%(b)); macro duration rem(duration a, duration b) duration(int(%(a)) % int(%(b))); // Type shenanegans with time arithmetic: macro time add(time a, duration b) time(int(%(a)) + int(%(b))); macro time sub(time a, duration b) time(int(%(a)) - int(%(b))); macro duration sub(time a, time b) duration(int(%(a)) - int(%(b))); macro void printSeconds(int d) { print(%(d) + " seconds"); }; macro void printMinutes(int d) { if %(d) >= 60 then print(%(d) / 60 + " minutes, "); printSeconds(%(d) % 60); }; macro void printHours(int d) { if %(d) >= 3600 then print(%(d) / 3600 + " hours, "); printMinutes(%(d) % 3600); }; macro void printDays(int d) { if %(d) >= 86400 then print(%(d) / 86400 + " days, "); printHours(%(d) % 86400); }; macro void printYears(int d) { if %(d) >= 31536000 then print(%(d) / 31536000 + " years, "); printDays(%(d) % 31536000); }; macro void print(duration d) printYears(int(%(d))); //----------------------- Ops on Files --------------------------- // A fileContents var will be represented by its filename. // But its meaning will be synonymous with its // contents of the named file rather than the name itself. // // When you declare a fileContents variable but before it // is assigned to refer to a particular file, it refers // to /dev/null by default. // macro fileContents new(fileContents x) { code:set %="/dev/null";; src:"$%";; dst:%;; }; // Returns the full path of the file as a string: macro string filename(fileContents f) src:%(f);; macro fileContents assign(fileContents a, fileContents b) { code:cp %(b) %(a) src:%(a);; }; macro fileContents assign(fileContents a, string b) { code:echo %(b) > %(a);; src:%(a);; }; macro fileContents assign(fileContents a, int b) { code:echo %(b) > %(a);; src:%(a);; }; macro fileContents fileContents(string name) src:%(name);; macro fileContents tempFile(string ext) { code:if ( %(ext) == "" ) then code: set %=~/".remove/T$$_%.tmp";; code:else code: set %=~/".remove/T$$_%."%(ext);; code:endif code:touch "$%";; src:"$%";; }; macro int int(fileContents f) { code:set %=(`head -1 %(f)`);; code:if ( $#% > 0 ) then;; code: set %="$%[1]";; code:else;; code: set %=0;; code:endif;; src:${%};; }; macro string string(fileContents f) { code:set %=`head -c 250 %(f)`;; src:"$%";; }; macro fileContents add(fileContents a, fileContents b) addDst(a, b, tempFile(extension(filename(%(a))))); macro fileContents add(string a, fileContents b) addDst(a, b, tempFile(extension(filename(%(b))))); macro fileContents add(fileContents a, string b) addDst(a, b, tempFile(extension(filename(%(a))))); macro fileContents addDst(fileContents a, fileContents b, fileContents c) { code:cat %(a) %(b) > %(c) src:%(c);; }; macro fileContents addDst(string a, fileContents b, fileContents c) { code:echo -n %(a) > %(c) code:cat %(b) >> %(c) src:%(c);; }; macro fileContents addDst(fileContents a, string b, fileContents c) { code:cat %(a) > %(c) code:echo -n %(b) >> %(c) src:%(c);; }; macro void print(fileContents f) { code:cat %(f);; }; macro void println(fileContents f) { code:cat %(f);; code:echo "";; }; //---------------------- These are just string methods, but relate to filenames ----------------- macro time modifyTime(string f) { code:@ % = ( -M %(f) );; src:${%};; }; macro time accessTime(string f) { code:@ % = ( -A %(f) );; src:${%};; }; macro time changeTime(string f) { code:@ % = ( -C %(f) );; src:${%};; }; macro int fileSize(string f) { code:@ % = ( -Z %(f) );; src:${%};; }; // Just the extension: macro string extension(string f) { code:set %=%(f);; code:set %="$%:e";; src:"$%";; }; // Full path without the extension: macro string basename(string f) { code:set %=%(f);; code:set %="$%:r";; src:"$%";; }; // Just the file w/out the directory: macro string fileTail(string f) { code:set %=%(f);; code:set %="$%:t";; src:"$%";; }; // Parent directory: macro string parent(string f) { code:set %=%(f);; code:set %="$%:h";; src:"$%";; }; macro bool fileExists (string f) src:( -e %(f) );; macro bool isPlainFile (string f) src:( -f %(f) );; macro bool isDirectory (string f) src:( -d %(f) );; macro bool isSymlink (string f) src:( -l %(f) );; macro bool canReadFile (string f) src:( -r %(f) );; macro bool canWriteFile(string f) src:( -w %(f) );; macro bool canExecFile (string f) src:( -x %(f) );; macro stringList filesIn(string dir) { code:if ( -d %(dir) ) then;; code: set %=(%(dir)/{.[.],*});; code: shift %;; code:else;; code: set %="";; code:endif;; src:%;; }; //------------------------- Ops on URLs ------------------------------ macro fileContents getUrlTo(url u, fileContents dst) { code:wget -q %(u) -O %(dst);; code:if ($status) then;; code: echo "Error fetching "%(u);; code: exit $status;; code:endif src:%(dst);; }; macro fileContents urlContents(string url) getUrlTo(%(url), tempFile(extension(%(url)))); macro fileContents urlContents(string url, string ext) getUrlTo(%(url), tempFile(%(ext))); //----------------------- Support for function calls ---------------------- // _rv() is the return variable. macro fileContents _rv() fileContents("/tmp/synsh_RV"); macro void return(int i) { _rv() = %(i); code:exit 0;; }; macro void return(string s) { _rv() = %(s); code:exit 0;; }; macro void fail(string s) { code:echo "ERROR:" %(s);; code:exit 1;; };