blob: f92433f956998df64d3d0fc859e2ae74e01a7505 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// $Id: parsing.c 9142 2015-02-04 22:17:29Z Zesstra $
Zesstra0f6a3022018-11-07 00:44:32 +01002#pragma strict_types, rtt_checks
Zesstra0d64cca2020-03-09 21:03:56 +01003#pragma range_check
MG Mud User88f12472016-06-24 23:31:02 +02004#pragma no_clone
MG Mud User88f12472016-06-24 23:31:02 +02005
Zesstra07210ee2018-11-08 20:57:14 +01006protected functions virtual inherit "/std/util/path";
7
MG Mud User88f12472016-06-24 23:31:02 +02008#include <files.h>
9#include <wizlevels.h>
10#include <logging.h>
11#include <regexp.h>
Zesstraf22b6a82018-11-07 22:39:55 +010012#include <defines.h>
MG Mud User88f12472016-06-24 23:31:02 +020013#define NEED_PROTOTYPES
14#include <magier.h>
15#include <thing/properties.h>
16#include <player.h>
17
18//
19// glob2regexp: Argument von glob in Regexp umwandeln
20// str: Argument (als Referenz)
21//
22
23static string glob2regexp(string str)
24{
25 str=regreplace(str,"([\\.\\^\\$\\[\\]\\(\\)])","\\\\\\1",RE_TRADITIONAL|1);
26 str=regreplace(str,"\\*",".*",RE_TRADITIONAL|1);
27 return sprintf("^%s$",regreplace(str,"?",".",RE_TRADITIONAL|1));
28}
29
30//
31// to_filename: Argument in Dateinamen umwandeln
32// str: Argument
33// Rueckgabe: Dateiname
34//
35
Vanion50652322020-03-10 21:13:25 +010036static string to_filename(string str)
MG Mud User88f12472016-06-24 23:31:02 +020037{
Arathorn135f7682021-03-16 23:25:52 +010038 string *tmp,p;
MG Mud User88f12472016-06-24 23:31:02 +020039// Testen ob .. in einem Filenamenabschnitt, falls Version <3.2.5
40 tmp=explode(str,"/");
41// Testen auf Pfadvariable
42 if (sizeof(tmp[0]) && tmp[0][0]=='$'
43 && m_contains(&p,QueryProp(P_VARIABLES),tmp[0][1..]))
44 tmp[0]=p;
45// Pfad absolut machen (Hat danach noch Wildcards drinnen) oder auch nicht
Zesstra07210ee2018-11-08 20:57:14 +010046 return normalize_path(implode(tmp,"/"), getuid(), 1);
MG Mud User88f12472016-06-24 23:31:02 +020047}
48
49
50//
51// _parseargs(): Kommandozeilenabschnitt parsen
52// str: Kommandozeilenabschnitt
53// line: Array von geparsten Kommandozeilenabschnitten (Referenz)
54// flags: Als Referenz uebergebener Flag-Wert
55// opts: Erlaubte Flags
56// build_fn: Filenamen aendern
57//
58
59private void _parseargs(string str, string *line,int flags,string opts,
60 int build_fn )
61{
62
63// Strings in "" erhalten
64 if(str[0] == "\""[0])
65 {
66 line += ({ str[1..<2] });
67 return;
68 }
69// Flags parsen
70 if(str[0] == '-')
71 {
72 int i,j;
73 i=sizeof(str);
Bugfix7e7c3402021-08-30 09:40:33 +020074 if(i == 1 && query_verb() == "cd")
75 {
76 flags |= CD_B;
77 }
78 else
79 {
80 while(i--)
Bugfixc05b9a32021-08-30 09:43:49 +020081 {
Bugfix7e7c3402021-08-30 09:40:33 +020082 if (str[i]!='-')
MG Mud User88f12472016-06-24 23:31:02 +020083 {
Bugfix7e7c3402021-08-30 09:40:33 +020084 if((j = member(opts, str[i])) != -1)
85 flags |= (1 << j);
86 else
87 {
88 flags=-1;
89 printf("Das Flag '-%c' wird von dem Befehl '%s' nicht "
90 "unterstuetzt.\n",str[i],query_verb()||"");
91 }
MG Mud User88f12472016-06-24 23:31:02 +020092 }
Bugfixc05b9a32021-08-30 09:43:49 +020093 }
Bugfix7e7c3402021-08-30 09:40:33 +020094 }
MG Mud User88f12472016-06-24 23:31:02 +020095 return;
96 }
97 if (build_fn)
98 {
Vanion50652322020-03-10 21:13:25 +010099 if (str=to_filename(str)) line+=({ str });
MG Mud User88f12472016-06-24 23:31:02 +0200100 }
101 else
102 line+= ({ str });
103}
104
105
106//
107// parseargs() - zerlegt Kommandozeile in ein Array:
108// cmdline: Kommandozeile
109// flags: Als Referenz uebergebener leerer Integerwert. Enthaelt danach
110// die Flags
111// opts: String mit erlaubten Optionen
112// build_fn: Filenamen umbauen?
113// Rueckgabe: Array der Kommandozeilenargumente (ausser Flags)
114//
115
116static string *parseargs(string cmdline,int flags, string opts,int build_fn)
117{
MG Mud User88f12472016-06-24 23:31:02 +0200118 string *line;
119 line=({});
120 if (!sizeof(cmdline)) return ({});
121 map(regexplode(cmdline,"[\"][^\"]*[\"]| ", RE_TRADITIONAL)-({" ", ""}),
122 #'_parseargs, &line, &flags,opts, build_fn);
123 return line - ({""});
124}
125
126//
127// _vc_map: VC-Objektnamen zu Arrays umwandeln ({ name, -1, program_time() })
128//
129
130private int *_vc_map(object ob,mixed *list)
131{
132 list+=({ explode(object_name(ob),"/")[<1],-1,program_time(ob) });
133 return 0;
134}
135
136
137//
138// _get_files: Filedaten beim Rekursiven kopieren erstellen
139// dirname: Bearbeitetes Verzeichnis
140// mask: Maske, der Dateinamen genuegen muessen
141// mode: Welche Daten werden benoetigt? (siehe magier.h)
142// dest: In welches Verzeichnis soll kopiert werden?
143// Rueckgabe: Alist mit den Dateiinformationen
144//
145
Zesstra0f6a3022018-11-07 00:44:32 +0100146private varargs mixed *_get_files(string dirname,string mask,int mode,
147 string dest)
MG Mud User88f12472016-06-24 23:31:02 +0200148{
MG Mud User88f12472016-06-24 23:31:02 +0200149 //DEBUG("_GF: DIRNAME " + dirname);
Zesstra0f6a3022018-11-07 00:44:32 +0100150 mixed *data=get_dir(dirname+"*",GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES);
MG Mud User88f12472016-06-24 23:31:02 +0200151 if(!sizeof(data)) return ({});
Bugfix87556ab2021-03-16 22:04:35 +0100152 < <int|string>* >* files=({});
Zesstra0f6a3022018-11-07 00:44:32 +0100153
Zesstracc3f2502018-11-14 23:46:47 +0100154 while(1)
MG Mud User88f12472016-06-24 23:31:02 +0200155 {
Bugfix87556ab2021-03-16 22:04:35 +0100156 < <int|string>* >* tmp=({});
Zesstra0f6a3022018-11-07 00:44:32 +0100157 string base=data[BASENAME];
158 string fullname=dirname+base;
159 if (base!="." && base!=".."
160 && (!(mode==MODE_GREP && base=="RCS"))
161 && ((data[FILESIZE]==FSIZE_DIR
162 && sizeof(tmp=_get_files(fullname+"/",mask,mode,dest+base+"/"))
163 && mode!=MODE_RM)
164 || !mask
165 || sizeof(regexp(({ base }),mask, RE_TRADITIONAL))) )
MG Mud User88f12472016-06-24 23:31:02 +0200166 {
167 //DEBUG("_GF: ADDING FILE " + fullname);
168 files+= ({ data[0..2]+({ fullname,dirname,dest+base,
169 sizeof(tmp) }) });
170 }
171 if (sizeof(files)+sizeof(tmp)>MAX_ARRAY_SIZE)
172 raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
173 files+=tmp;
Zesstracc3f2502018-11-14 23:46:47 +0100174 if (sizeof(data) > 3)
175 data=data[3..];
176 else
177 break;
MG Mud User88f12472016-06-24 23:31:02 +0200178 }
Zesstraf22b6a82018-11-07 22:39:55 +0100179
MG Mud User88f12472016-06-24 23:31:02 +0200180 if(sizeof(files)>300&&!IS_ARCH(this_object()))
181 // Tod allen Laggern :o)
182 raise_error("Zu viele Files (>300)!! Abgebrochen!\n");
183 return files;
184}
185
186
187//
188// _get_matching: Rekursive Funktion zum ermitteln der Files, wenn mit Maske
189// gearbeitet wird (z.B. cp -m /bla/*/* /ziel *.c)
190// pathmask: Array, das die einzelnen Elemente der Maske (Arg1) enthaelt
191// (per efun:old_explode(arg1,"/"))
192// depth: Aktuelles Element von pathmask
193// path: implode(pathmask[0..depth],"/");
194// mode: Welche Daten werden benoetigt? (siehe magier.h)
195// flags: Welche Flags wurden gesetzt?
196// dest: Zielverzeichnis (beim kopieren/moven)
197// filemask: Maske, der die Files genuegen muessen
198// Rueckgabe: Alist mit den Dateiinformationen
199//
200
201private mixed *_get_matching(string *pathmask, int depth, string path,
202 int mode, int recursive, string dest,string filemask)
203{
MG Mud User88f12472016-06-24 23:31:02 +0200204 //DEBUG("_GM: PM: " + pathmask[depth]);
205 //DEBUG("_GM: FM: " + filemask);
Zesstraf22b6a82018-11-07 22:39:55 +0100206
207 // Pfad normalisieren (ggf. Platzhalter expandieren)
Zesstra07210ee2018-11-08 20:57:14 +0100208 string p=normalize_path(path+pathmask[depth++], getuid(), 1);
Zesstraf22b6a82018-11-07 22:39:55 +0100209 mixed *data=get_dir(p, GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES)||({});
Zesstra0f6a3022018-11-07 00:44:32 +0100210 if (!sizeof(data))
211 return ({});
212
Zesstraf22b6a82018-11-07 22:39:55 +0100213 // Bemerkung: path beginnt als "/" und wird nach und nach mit base
214 // verlaengert, daher muss das nicht explizit normalisiert werden. dest
215 // wurde bereits vom Aufrufer normalisiert und wird hier nur durchgereicht.
216
Zesstra0f6a3022018-11-07 00:44:32 +0100217 mixed *files=({});
MG Mud User88f12472016-06-24 23:31:02 +0200218 while(sizeof(data))
219 {
Zesstra0f6a3022018-11-07 00:44:32 +0100220 string base=data[BASENAME];
221 if (base=="." || base=="..")
MG Mud User88f12472016-06-24 23:31:02 +0200222 {
223 data=data[3..];
224 continue;
225 }
Zesstra0f6a3022018-11-07 00:44:32 +0100226 string full=path+base;
MG Mud User88f12472016-06-24 23:31:02 +0200227 //DEBUG("_GM: FULL: " + full);
Zesstra0f6a3022018-11-07 00:44:32 +0100228 mixed *tmp;
229 if ((data[FILESIZE]==FSIZE_DIR) && (sizeof(pathmask)>depth)
230 && (!(mode==MODE_GREP && base=="RCS")))
MG Mud User88f12472016-06-24 23:31:02 +0200231 {
232 //DEBUG("DESCEND INTO " + full);
233 tmp=_get_matching(pathmask,depth,full+"/",mode,recursive,
Zesstra0f6a3022018-11-07 00:44:32 +0100234 (recursive ? dest+base+"/" : dest),filemask);
MG Mud User88f12472016-06-24 23:31:02 +0200235 }
236 else tmp=({});
Zesstra0f6a3022018-11-07 00:44:32 +0100237
MG Mud User88f12472016-06-24 23:31:02 +0200238 //DEBUG("DEPTH: " + depth + " : " + sizeof(pathmask));
Zesstra0f6a3022018-11-07 00:44:32 +0100239 if((!filemask && (depth==sizeof(pathmask)))
240 || (filemask && (depth+2 > sizeof(pathmask))
241 && sizeof(regexp(({ base }),filemask,RE_TRADITIONAL)))
242 || ((mode==MODE_CP || mode==MODE_MV
243 || (filemask && (mode==MODE_RM)
244 && sizeof(regexp(({ base}),filemask,RE_TRADITIONAL))))
245 && sizeof(tmp)) )
MG Mud User88f12472016-06-24 23:31:02 +0200246 {
247 //DEBUG("ADDING: " + base+ " : "+ full );
248 files+=({ data[0..2]+({ full, path, dest+base,sizeof(tmp)}) });
249 }
Zesstra0f6a3022018-11-07 00:44:32 +0100250 if (sizeof(files) + sizeof(tmp) > MAX_ARRAY_SIZE)
MG Mud User88f12472016-06-24 23:31:02 +0200251 raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
252 files+=tmp;
Zesstra20b907f2018-11-08 00:34:03 +0100253 if(sizeof(data)>3)
254 data=data[3..];
255 else
256 break;
MG Mud User88f12472016-06-24 23:31:02 +0200257 }
258 if(sizeof(files)>300&&!IS_ARCH(this_object()))
259 // Tod allen Laggern!
260 raise_error("Zu viele Files (>300)!! Abgebrochen!\n");
261 return files;
262}
263
264
265//
266// get_files: Basisroutine zum Ermitteln der zu bearbeitenden Dateien
267// filename: Pfadmaske, Verzeichnisname, Dateiname, der bearbeitet werden
268// soll
269// mode: Welche Daten werden benoetigt? (siehe magier.h)
270// recursive: Auch Unterverzeichnisse bearbeiten?
271// dest: Wenn kopiert werden soll: wohin?
272// filemask: Maske, der die Dateinamen genuegen muessen
273// Rueckgabe: Alist mit den Dateiinformationen
274//
275
Zesstra0f6a3022018-11-07 00:44:32 +0100276static varargs mixed *get_files(string filename, int mode, int recursive,
277 string dest, string filemask)
278{
Zesstraf22b6a82018-11-07 22:39:55 +0100279 // Bemerkung. dest wurde bereits vom Aufrufer normalisiert.
280
MG Mud User88f12472016-06-24 23:31:02 +0200281 // DEBUG("GF: " + filename);
282 // DEBUG("REC: " + recursive + " MODE: " + mode);
283 // if (dest[<1..<1]!="/") DEBUG("DEST: " + dest);
284 if (filename=="/")
Zesstraf22b6a82018-11-07 22:39:55 +0100285 {
MG Mud User88f12472016-06-24 23:31:02 +0200286 switch (mode)
287 {
288 case MODE_LSA: return ({({ "", -2, 0,"","","",0 })});
289 default: if (!recursive) return ({});
290 break;
291 }
Zesstraf22b6a82018-11-07 22:39:55 +0100292 }
293
294 // Normalisiertes Pfadarray besorgen
bugfixd94d0932020-04-08 11:27:13 +0200295 string *patharray=({string*})master()->path_array(filename);
Zesstraf22b6a82018-11-07 22:39:55 +0100296 // und daraus auch filename neu erzeugen
297 filename=implode(patharray, "/");
Zesstra0f6a3022018-11-07 00:44:32 +0100298
299 mixed *data=get_dir(filename,GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES)||({});
300 if(!sizeof(data)
301 && (mode==MODE_UPD || mode==MODE_MORE || mode==MODE_ED))
302 data=get_dir(filename+".c",GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES) || ({});
303
304 if ((mode==MODE_LSA||mode==MODE_LSB))
305 {
Zesstra0f6a3022018-11-07 00:44:32 +0100306 object vcompiler =
307 find_object(implode(patharray[0..<2],"/")+"/virtual_compiler");
Arathorn9845d112020-01-08 22:02:03 +0100308
309 object *vrooms = ({});
310 if (vcompiler)
bugfixd94d0932020-04-08 11:27:13 +0200311 vrooms = ({object*})vcompiler->QueryObjects();
Arathorn74b00cb2020-08-16 01:32:22 +0200312
313 // Nicht alle VCs liefern ihre Objektliste aus.
314 map(vrooms||({}), #'_vc_map, &data);
Zesstra0f6a3022018-11-07 00:44:32 +0100315 }
316 mixed *files=({});
MG Mud User88f12472016-06-24 23:31:02 +0200317 if (sizeof(data)) // passende files
318 {
319 mixed *subfiles;
320 subfiles=({});
Zesstra0f6a3022018-11-07 00:44:32 +0100321 string path=implode(patharray[0..<2],"/")+"/";
MG Mud User88f12472016-06-24 23:31:02 +0200322 while (sizeof(data))
323 {
324 subfiles=({});
Zesstra0f6a3022018-11-07 00:44:32 +0100325 string base=data[BASENAME];
MG Mud User88f12472016-06-24 23:31:02 +0200326 if (mode==MODE_LSB||(base!="."&&base!=".."))
327 {
328 //DEBUG("PATH: " + path+" BASE: " + base + " MODE: " + mode);
Zesstra0f6a3022018-11-07 00:44:32 +0100329 string full=path+base;
330 string dest2;
331 if (dest=="/" || file_size(dest[0..<2])==FSIZE_DIR)
332 dest2 = dest+base;
333 else
334 dest2 = dest[0..<2];
335
MG Mud User88f12472016-06-24 23:31:02 +0200336 //DEBUG("DEST: " + dest);
Zesstra0f6a3022018-11-07 00:44:32 +0100337 if (recursive && data[FILESIZE]==FSIZE_DIR) // Verzeichnis, Rekursiv
MG Mud User88f12472016-06-24 23:31:02 +0200338 subfiles=_get_files(full+"/",filemask,mode,dest2+"/");
Zesstra0f6a3022018-11-07 00:44:32 +0100339 if (!(filemask && !sizeof(subfiles)
340 && !sizeof(regexp(({ base }),filemask,RE_TRADITIONAL))))
MG Mud User88f12472016-06-24 23:31:02 +0200341 {
Zesstra0f6a3022018-11-07 00:44:32 +0100342 if (!filemask || mode!=MODE_RM)
MG Mud User88f12472016-06-24 23:31:02 +0200343 files+=({ data[0..2]+({ full, path, dest2,sizeof(subfiles)}) });
Zesstra0f6a3022018-11-07 00:44:32 +0100344 if (sizeof(files)+sizeof(subfiles) > MAX_ARRAY_SIZE)
MG Mud User88f12472016-06-24 23:31:02 +0200345 raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
346 files+=subfiles;
347 }
348 }
Zesstra0524def2018-11-07 22:48:37 +0100349 if (sizeof(data)>3)
350 data=data[3..];
351 else
352 break;
MG Mud User88f12472016-06-24 23:31:02 +0200353 }
354 return files;
355 }
356// File existiert nicht -> Wildcard oder tatsaechlich nicht existent
357// Behandeln je nach mode
358 switch(mode)
359 {
360 case MODE_CP:
361 case MODE_MV:
362 case MODE_CD:
363 case MODE_LSA:
364 files=_get_matching(patharray+(filemask?({ "*" }):({})),1,"/",mode,
365 recursive,dest,filemask);
366 break;
367 default: break;
368 }
369 return files;
370}
371
372
373//
374// file_list(): Liste der Fileinformationen
375// files: Array der Filenamen MIT Wildcards
376// mode: Welche Daten werden benoetigt
377// recursive: Rekursiv listen?
378// dest: Zielverzeichnis
379// mask: Maske (regexp, wenn definiert)
380// Rueckgabe: Liste der betroffenen Files
381//
382
Zesstra0f6a3022018-11-07 00:44:32 +0100383static varargs mixed *file_list(string *files, int mode, int recursive,
384 string dest, string mask)
MG Mud User88f12472016-06-24 23:31:02 +0200385{
Bugfix87556ab2021-03-16 22:04:35 +0100386 < <int|string>* >* list=({});
MG Mud User88f12472016-06-24 23:31:02 +0200387 if (mask) mask=glob2regexp(mask);
Zesstraf22b6a82018-11-07 22:39:55 +0100388 // dest muss einmal normalisiert werden, dann muss es das in den gerufenen
389 // (rekursiven) Funktionen nicht immer nochmal gemacht werden.
Zesstra07210ee2018-11-08 20:57:14 +0100390 dest=normalize_path(dest, getuid(), 1);
Zesstraf22b6a82018-11-07 22:39:55 +0100391
Zesstra0f6a3022018-11-07 00:44:32 +0100392 foreach(string file: files)
MG Mud User88f12472016-06-24 23:31:02 +0200393 {
394 // Abschliessenden / von Pfadnamen abschneiden, weil in diesem Fall
395 // die Inhalte der ersten Unterverzeichnisebene mit ausgegeben
396 // wurden. Ursache hierfuer ist ein Fix an full_path_array() im
397 // Masterobjekt, der dazu fuehrte, dass get_dir() den abschliessenden /
398 // des uebergebenen Pfades jetzt korrekt behandelt. \o/
Zesstra0f6a3022018-11-07 00:44:32 +0100399 if ( sizeof(file) > 1 && file[<1] == '/' )
MG Mud User88f12472016-06-24 23:31:02 +0200400 {
Zesstra0f6a3022018-11-07 00:44:32 +0100401 file = file[0..<2];
402 if ( !sizeof(file) )
MG Mud User88f12472016-06-24 23:31:02 +0200403 continue;
404 }
Zesstra0f6a3022018-11-07 00:44:32 +0100405 string err=catch(list += get_files(file,mode,recursive,dest,mask));
406 if (err)
MG Mud User88f12472016-06-24 23:31:02 +0200407 {
408 printf("Fehler aufgetreten: %s\n",err);
409 log_file(SHELLLOG("FILE_LIST"),
410 sprintf("%s fuehrte folgendes Kommando aus: (Zeit: %s)\n"
411 " >>%s %s<<\n"
412 " Folgender Fehler trat dabei auf:\n"
413 " %s\n\n",
414 capitalize(getuid())||"<Unbekannt>",dtime(time()),
415 query_verb()||"*",_unparsed_args()||"*",err||"*"));
416 return ({});
417 }
418 }
419 return list;
420}