| // $Id: parsing.c 9142 2015-02-04 22:17:29Z Zesstra $ |
| #pragma strict_types, rtt_checks |
| #pragma range_check, pedantic |
| #pragma no_clone |
| |
| #include <files.h> |
| #include <wizlevels.h> |
| #include <logging.h> |
| #include <regexp.h> |
| #include <defines.h> |
| #define NEED_PROTOTYPES |
| #include <magier.h> |
| #include <thing/properties.h> |
| #include <player.h> |
| |
| // |
| // glob2regexp: Argument von glob in Regexp umwandeln |
| // str: Argument (als Referenz) |
| // |
| |
| static string glob2regexp(string str) |
| { |
| str=regreplace(str,"([\\.\\^\\$\\[\\]\\(\\)])","\\\\\\1",RE_TRADITIONAL|1); |
| str=regreplace(str,"\\*",".*",RE_TRADITIONAL|1); |
| return sprintf("^%s$",regreplace(str,"?",".",RE_TRADITIONAL|1)); |
| } |
| |
| // |
| // to_filename: Argument in Dateinamen umwandeln |
| // str: Argument |
| // Rueckgabe: Dateiname |
| // |
| |
| static mixed to_filename(string str) |
| { |
| string *tmp,p,newfn; |
| int i; |
| // Testen ob .. in einem Filenamenabschnitt, falls Version <3.2.5 |
| tmp=explode(str,"/"); |
| // Testen auf Pfadvariable |
| if (sizeof(tmp[0]) && tmp[0][0]=='$' |
| && m_contains(&p,QueryProp(P_VARIABLES),tmp[0][1..])) |
| tmp[0]=p; |
| // Pfad absolut machen (Hat danach noch Wildcards drinnen) oder auch nicht |
| return master()->make_path_absolute(implode(tmp,"/")); |
| } |
| |
| |
| // |
| // _parseargs(): Kommandozeilenabschnitt parsen |
| // str: Kommandozeilenabschnitt |
| // line: Array von geparsten Kommandozeilenabschnitten (Referenz) |
| // flags: Als Referenz uebergebener Flag-Wert |
| // opts: Erlaubte Flags |
| // build_fn: Filenamen aendern |
| // |
| |
| private void _parseargs(string str, string *line,int flags,string opts, |
| int build_fn ) |
| { |
| |
| // Strings in "" erhalten |
| if(str[0] == "\""[0]) |
| { |
| line += ({ str[1..<2] }); |
| return; |
| } |
| // Flags parsen |
| if(str[0] == '-') |
| { |
| int i,j; |
| i=sizeof(str); |
| while(i--) |
| if (str[i]!='-') |
| { |
| if((j = member(opts, str[i])) != -1) |
| flags |= (1 << j); |
| else |
| { |
| flags=-1; |
| printf("Das Flag '-%c' wird von dem Befehl '%s' nicht " |
| "unterstuetzt.\n",str[i],query_verb()||""); |
| } |
| } |
| return; |
| } |
| if (build_fn) |
| { |
| if (str=(string)to_filename(str)) line+=({ str }); |
| } |
| else |
| line+= ({ str }); |
| } |
| |
| |
| // |
| // parseargs() - zerlegt Kommandozeile in ein Array: |
| // cmdline: Kommandozeile |
| // flags: Als Referenz uebergebener leerer Integerwert. Enthaelt danach |
| // die Flags |
| // opts: String mit erlaubten Optionen |
| // build_fn: Filenamen umbauen? |
| // Rueckgabe: Array der Kommandozeilenargumente (ausser Flags) |
| // |
| |
| static string *parseargs(string cmdline,int flags, string opts,int build_fn) |
| { |
| int i; |
| string *line; |
| line=({}); |
| if (!sizeof(cmdline)) return ({}); |
| map(regexplode(cmdline,"[\"][^\"]*[\"]| ", RE_TRADITIONAL)-({" ", ""}), |
| #'_parseargs, &line, &flags,opts, build_fn); |
| return line - ({""}); |
| } |
| |
| // |
| // _vc_map: VC-Objektnamen zu Arrays umwandeln ({ name, -1, program_time() }) |
| // |
| |
| private int *_vc_map(object ob,mixed *list) |
| { |
| list+=({ explode(object_name(ob),"/")[<1],-1,program_time(ob) }); |
| return 0; |
| } |
| |
| |
| // |
| // _get_files: Filedaten beim Rekursiven kopieren erstellen |
| // dirname: Bearbeitetes Verzeichnis |
| // mask: Maske, der Dateinamen genuegen muessen |
| // mode: Welche Daten werden benoetigt? (siehe magier.h) |
| // dest: In welches Verzeichnis soll kopiert werden? |
| // Rueckgabe: Alist mit den Dateiinformationen |
| // |
| |
| private varargs mixed *_get_files(string dirname,string mask,int mode, |
| string dest) |
| { |
| //DEBUG("_GF: DIRNAME " + dirname); |
| mixed *data=get_dir(dirname+"*",GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES); |
| if(!sizeof(data)) return ({}); |
| mixed *files=({}); |
| |
| while(sizeof(data)) |
| { |
| mixed *tmp=({}); |
| string base=data[BASENAME]; |
| string fullname=dirname+base; |
| if (base!="." && base!=".." |
| && (!(mode==MODE_GREP && base=="RCS")) |
| && ((data[FILESIZE]==FSIZE_DIR |
| && sizeof(tmp=_get_files(fullname+"/",mask,mode,dest+base+"/")) |
| && mode!=MODE_RM) |
| || !mask |
| || sizeof(regexp(({ base }),mask, RE_TRADITIONAL))) ) |
| { |
| //DEBUG("_GF: ADDING FILE " + fullname); |
| files+= ({ data[0..2]+({ fullname,dirname,dest+base, |
| sizeof(tmp) }) }); |
| } |
| if (sizeof(files)+sizeof(tmp)>MAX_ARRAY_SIZE) |
| raise_error("Zu viele Files (>3000)!! Abgebrochen!\n"); |
| files+=tmp; |
| data=data[3..]; |
| } |
| |
| if(sizeof(files)>300&&!IS_ARCH(this_object())) |
| // Tod allen Laggern :o) |
| raise_error("Zu viele Files (>300)!! Abgebrochen!\n"); |
| return files; |
| } |
| |
| |
| // |
| // _get_matching: Rekursive Funktion zum ermitteln der Files, wenn mit Maske |
| // gearbeitet wird (z.B. cp -m /bla/*/* /ziel *.c) |
| // pathmask: Array, das die einzelnen Elemente der Maske (Arg1) enthaelt |
| // (per efun:old_explode(arg1,"/")) |
| // depth: Aktuelles Element von pathmask |
| // path: implode(pathmask[0..depth],"/"); |
| // mode: Welche Daten werden benoetigt? (siehe magier.h) |
| // flags: Welche Flags wurden gesetzt? |
| // dest: Zielverzeichnis (beim kopieren/moven) |
| // filemask: Maske, der die Files genuegen muessen |
| // Rueckgabe: Alist mit den Dateiinformationen |
| // |
| |
| private mixed *_get_matching(string *pathmask, int depth, string path, |
| int mode, int recursive, string dest,string filemask) |
| { |
| //DEBUG("_GM: PM: " + pathmask[depth]); |
| //DEBUG("_GM: FM: " + filemask); |
| |
| // Pfad normalisieren (ggf. Platzhalter expandieren) |
| string p=master()->normalize_path(path+pathmask[depth++], |
| getuid(RPL||PL), 1); |
| mixed *data=get_dir(p, GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES)||({}); |
| if (!sizeof(data)) |
| return ({}); |
| |
| // Bemerkung: path beginnt als "/" und wird nach und nach mit base |
| // verlaengert, daher muss das nicht explizit normalisiert werden. dest |
| // wurde bereits vom Aufrufer normalisiert und wird hier nur durchgereicht. |
| |
| mixed *files=({}); |
| while(sizeof(data)) |
| { |
| string base=data[BASENAME]; |
| if (base=="." || base=="..") |
| { |
| data=data[3..]; |
| continue; |
| } |
| string full=path+base; |
| //DEBUG("_GM: FULL: " + full); |
| mixed *tmp; |
| if ((data[FILESIZE]==FSIZE_DIR) && (sizeof(pathmask)>depth) |
| && (!(mode==MODE_GREP && base=="RCS"))) |
| { |
| //DEBUG("DESCEND INTO " + full); |
| tmp=_get_matching(pathmask,depth,full+"/",mode,recursive, |
| (recursive ? dest+base+"/" : dest),filemask); |
| } |
| else tmp=({}); |
| |
| //DEBUG("DEPTH: " + depth + " : " + sizeof(pathmask)); |
| if((!filemask && (depth==sizeof(pathmask))) |
| || (filemask && (depth+2 > sizeof(pathmask)) |
| && sizeof(regexp(({ base }),filemask,RE_TRADITIONAL))) |
| || ((mode==MODE_CP || mode==MODE_MV |
| || (filemask && (mode==MODE_RM) |
| && sizeof(regexp(({ base}),filemask,RE_TRADITIONAL)))) |
| && sizeof(tmp)) ) |
| { |
| //DEBUG("ADDING: " + base+ " : "+ full ); |
| files+=({ data[0..2]+({ full, path, dest+base,sizeof(tmp)}) }); |
| } |
| if (sizeof(files) + sizeof(tmp) > MAX_ARRAY_SIZE) |
| raise_error("Zu viele Files (>3000)!! Abgebrochen!\n"); |
| files+=tmp; |
| data=data[3..]; |
| } |
| if(sizeof(files)>300&&!IS_ARCH(this_object())) |
| // Tod allen Laggern! |
| raise_error("Zu viele Files (>300)!! Abgebrochen!\n"); |
| return files; |
| } |
| |
| |
| // |
| // get_files: Basisroutine zum Ermitteln der zu bearbeitenden Dateien |
| // filename: Pfadmaske, Verzeichnisname, Dateiname, der bearbeitet werden |
| // soll |
| // mode: Welche Daten werden benoetigt? (siehe magier.h) |
| // recursive: Auch Unterverzeichnisse bearbeiten? |
| // dest: Wenn kopiert werden soll: wohin? |
| // filemask: Maske, der die Dateinamen genuegen muessen |
| // Rueckgabe: Alist mit den Dateiinformationen |
| // |
| |
| static varargs mixed *get_files(string filename, int mode, int recursive, |
| string dest, string filemask) |
| { |
| // Bemerkung. dest wurde bereits vom Aufrufer normalisiert. |
| |
| // DEBUG("GF: " + filename); |
| // DEBUG("REC: " + recursive + " MODE: " + mode); |
| // if (dest[<1..<1]!="/") DEBUG("DEST: " + dest); |
| if (filename=="/") |
| { |
| switch (mode) |
| { |
| case MODE_LSA: return ({({ "", -2, 0,"","","",0 })}); |
| default: if (!recursive) return ({}); |
| break; |
| } |
| } |
| |
| // Normalisiertes Pfadarray besorgen |
| string *patharray=master()->path_array(filename, getuid(RPL||PL), 1); |
| // und daraus auch filename neu erzeugen |
| filename=implode(patharray, "/"); |
| |
| mixed *data=get_dir(filename,GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES)||({}); |
| if(!sizeof(data) |
| && (mode==MODE_UPD || mode==MODE_MORE || mode==MODE_ED)) |
| data=get_dir(filename+".c",GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES) || ({}); |
| |
| if ((mode==MODE_LSA||mode==MODE_LSB)) |
| { |
| string *vrooms; |
| object vcompiler = |
| find_object(implode(patharray[0..<2],"/")+"/virtual_compiler"); |
| if (vcompiler && pointerp(vrooms=(mixed *)vcompiler->QueryObjects())) |
| map(vrooms,#'_vc_map,&data); |
| } |
| mixed *files=({}); |
| if (sizeof(data)) // passende files |
| { |
| mixed *subfiles; |
| subfiles=({}); |
| string path=implode(patharray[0..<2],"/")+"/"; |
| while (sizeof(data)) |
| { |
| subfiles=({}); |
| string base=data[BASENAME]; |
| if (mode==MODE_LSB||(base!="."&&base!="..")) |
| { |
| //DEBUG("PATH: " + path+" BASE: " + base + " MODE: " + mode); |
| string full=path+base; |
| string dest2; |
| if (dest=="/" || file_size(dest[0..<2])==FSIZE_DIR) |
| dest2 = dest+base; |
| else |
| dest2 = dest[0..<2]; |
| |
| //DEBUG("DEST: " + dest); |
| if (recursive && data[FILESIZE]==FSIZE_DIR) // Verzeichnis, Rekursiv |
| subfiles=_get_files(full+"/",filemask,mode,dest2+"/"); |
| if (!(filemask && !sizeof(subfiles) |
| && !sizeof(regexp(({ base }),filemask,RE_TRADITIONAL)))) |
| { |
| if (!filemask || mode!=MODE_RM) |
| files+=({ data[0..2]+({ full, path, dest2,sizeof(subfiles)}) }); |
| if (sizeof(files)+sizeof(subfiles) > MAX_ARRAY_SIZE) |
| raise_error("Zu viele Files (>3000)!! Abgebrochen!\n"); |
| files+=subfiles; |
| } |
| } |
| if (sizeof(data)>3) |
| data=data[3..]; |
| else |
| break; |
| } |
| return files; |
| } |
| // File existiert nicht -> Wildcard oder tatsaechlich nicht existent |
| // Behandeln je nach mode |
| switch(mode) |
| { |
| case MODE_CP: |
| case MODE_MV: |
| case MODE_CD: |
| case MODE_LSA: |
| files=_get_matching(patharray+(filemask?({ "*" }):({})),1,"/",mode, |
| recursive,dest,filemask); |
| break; |
| default: break; |
| } |
| return files; |
| } |
| |
| |
| // |
| // file_list(): Liste der Fileinformationen |
| // files: Array der Filenamen MIT Wildcards |
| // mode: Welche Daten werden benoetigt |
| // recursive: Rekursiv listen? |
| // dest: Zielverzeichnis |
| // mask: Maske (regexp, wenn definiert) |
| // Rueckgabe: Liste der betroffenen Files |
| // |
| |
| static varargs mixed *file_list(string *files, int mode, int recursive, |
| string dest, string mask) |
| { |
| string *list=({}); |
| if (mask) mask=glob2regexp(mask); |
| // dest muss einmal normalisiert werden, dann muss es das in den gerufenen |
| // (rekursiven) Funktionen nicht immer nochmal gemacht werden. |
| dest=master()->normalize_path(dest, getuid(RPL||PL), 1); |
| |
| foreach(string file: files) |
| { |
| // Abschliessenden / von Pfadnamen abschneiden, weil in diesem Fall |
| // die Inhalte der ersten Unterverzeichnisebene mit ausgegeben |
| // wurden. Ursache hierfuer ist ein Fix an full_path_array() im |
| // Masterobjekt, der dazu fuehrte, dass get_dir() den abschliessenden / |
| // des uebergebenen Pfades jetzt korrekt behandelt. \o/ |
| if ( sizeof(file) > 1 && file[<1] == '/' ) |
| { |
| file = file[0..<2]; |
| if ( !sizeof(file) ) |
| continue; |
| } |
| string err=catch(list += get_files(file,mode,recursive,dest,mask)); |
| if (err) |
| { |
| printf("Fehler aufgetreten: %s\n",err); |
| log_file(SHELLLOG("FILE_LIST"), |
| sprintf("%s fuehrte folgendes Kommando aus: (Zeit: %s)\n" |
| " >>%s %s<<\n" |
| " Folgender Fehler trat dabei auf:\n" |
| " %s\n\n", |
| capitalize(getuid())||"<Unbekannt>",dtime(time()), |
| query_verb()||"*",_unparsed_args()||"*",err||"*")); |
| return ({}); |
| } |
| } |
| return list; |
| } |