blob: 555332d4471aa911710b4261e47c09dcdfb92153 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// $Id: parsing.c 9142 2015-02-04 22:17:29Z Zesstra $
2#pragma strict_types
3#pragma save_types
4//#pragma range_check
5#pragma no_clone
6#pragma pedantic
7
8#include <files.h>
9#include <wizlevels.h>
10#include <logging.h>
11#include <regexp.h>
12#define NEED_PROTOTYPES
13#include <magier.h>
14#include <thing/properties.h>
15#include <player.h>
16
17//
18// glob2regexp: Argument von glob in Regexp umwandeln
19// str: Argument (als Referenz)
20//
21
22static string glob2regexp(string str)
23{
24 str=regreplace(str,"([\\.\\^\\$\\[\\]\\(\\)])","\\\\\\1",RE_TRADITIONAL|1);
25 str=regreplace(str,"\\*",".*",RE_TRADITIONAL|1);
26 return sprintf("^%s$",regreplace(str,"?",".",RE_TRADITIONAL|1));
27}
28
29//
30// to_filename: Argument in Dateinamen umwandeln
31// str: Argument
32// Rueckgabe: Dateiname
33//
34
35static mixed to_filename(string str)
36{
37 string *tmp,p,newfn;
38 int i;
39// 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
46 return master()->make_path_absolute(implode(tmp,"/"));
47}
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);
74 while(i--)
75 if (str[i]!='-')
76 {
77 if((j = member(opts, str[i])) != -1)
78 flags |= (1 << j);
79 else
80 {
81 flags=-1;
82 printf("Das Flag '-%c' wird von dem Befehl '%s' nicht "
83 "unterstuetzt.\n",str[i],query_verb()||"");
84 }
85 }
86 return;
87 }
88 if (build_fn)
89 {
90 if (str=(string)to_filename(str)) line+=({ str });
91 }
92 else
93 line+= ({ str });
94}
95
96
97//
98// parseargs() - zerlegt Kommandozeile in ein Array:
99// cmdline: Kommandozeile
100// flags: Als Referenz uebergebener leerer Integerwert. Enthaelt danach
101// die Flags
102// opts: String mit erlaubten Optionen
103// build_fn: Filenamen umbauen?
104// Rueckgabe: Array der Kommandozeilenargumente (ausser Flags)
105//
106
107static string *parseargs(string cmdline,int flags, string opts,int build_fn)
108{
109 int i;
110 string *line;
111 line=({});
112 if (!sizeof(cmdline)) return ({});
113 map(regexplode(cmdline,"[\"][^\"]*[\"]| ", RE_TRADITIONAL)-({" ", ""}),
114 #'_parseargs, &line, &flags,opts, build_fn);
115 return line - ({""});
116}
117
118//
119// _vc_map: VC-Objektnamen zu Arrays umwandeln ({ name, -1, program_time() })
120//
121
122private int *_vc_map(object ob,mixed *list)
123{
124 list+=({ explode(object_name(ob),"/")[<1],-1,program_time(ob) });
125 return 0;
126}
127
128
129//
130// _get_files: Filedaten beim Rekursiven kopieren erstellen
131// dirname: Bearbeitetes Verzeichnis
132// mask: Maske, der Dateinamen genuegen muessen
133// mode: Welche Daten werden benoetigt? (siehe magier.h)
134// dest: In welches Verzeichnis soll kopiert werden?
135// Rueckgabe: Alist mit den Dateiinformationen
136//
137
138private varargs mixed *_get_files(string dirname,string mask,int mode,string dest)
139{
140 mixed *files,*tmp,*data;
141 string fullname,base;
142
143 //DEBUG("_GF: DIRNAME " + dirname);
144 data=get_dir(dirname+"*",7);
145 if(!sizeof(data)) return ({});
146 files=({});
147
148 while(sizeof(data))
149 {
150 tmp=({});
151 base=data[BASENAME];
152 fullname=dirname+base;
153 if (base!="."&&base!=".."&&(!(mode==MODE_GREP&&base=="RCS"))&&
154 ((data[FILESIZE]==-2&&
155 sizeof(tmp=_get_files(fullname+"/",mask,mode,
156 dest+base+"/"))&&mode!=MODE_RM)||!mask||sizeof(regexp(({ base }),mask, RE_TRADITIONAL))))
157 {
158 //DEBUG("_GF: ADDING FILE " + fullname);
159 files+= ({ data[0..2]+({ fullname,dirname,dest+base,
160 sizeof(tmp) }) });
161 }
162 if (sizeof(files)+sizeof(tmp)>MAX_ARRAY_SIZE)
163 raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
164 files+=tmp;
165 data=data[3..];
166 }
167
168 if(sizeof(files)>300&&!IS_ARCH(this_object()))
169 // Tod allen Laggern :o)
170 raise_error("Zu viele Files (>300)!! Abgebrochen!\n");
171 return files;
172}
173
174
175//
176// _get_matching: Rekursive Funktion zum ermitteln der Files, wenn mit Maske
177// gearbeitet wird (z.B. cp -m /bla/*/* /ziel *.c)
178// pathmask: Array, das die einzelnen Elemente der Maske (Arg1) enthaelt
179// (per efun:old_explode(arg1,"/"))
180// depth: Aktuelles Element von pathmask
181// path: implode(pathmask[0..depth],"/");
182// mode: Welche Daten werden benoetigt? (siehe magier.h)
183// flags: Welche Flags wurden gesetzt?
184// dest: Zielverzeichnis (beim kopieren/moven)
185// filemask: Maske, der die Files genuegen muessen
186// Rueckgabe: Alist mit den Dateiinformationen
187//
188
189private mixed *_get_matching(string *pathmask, int depth, string path,
190 int mode, int recursive, string dest,string filemask)
191{
192 mixed *data,*tmp,*files;
193 string base,full;
194
195 //DEBUG("_GM: PM: " + pathmask[depth]);
196 //DEBUG("_GM: FM: " + filemask);
197 data=get_dir(path+pathmask[depth++],GETDIR_NAMES|GETDIR_SIZES|GETDIR_DATES)||({});
198 if (!sizeof(data)) return ({});
199 files=({});
200 while(sizeof(data))
201 {
202 if ((base=data[BASENAME])=="."||base=="..")
203 {
204 data=data[3..];
205 continue;
206 }
207 full=path+base;
208 //DEBUG("_GM: FULL: " + full);
209 if ((data[FILESIZE]==-2)&&(sizeof(pathmask)>depth)&&
210 (!(mode==MODE_GREP&&base=="RCS")))
211 {
212 //DEBUG("DESCEND INTO " + full);
213 tmp=_get_matching(pathmask,depth,full+"/",mode,recursive,
214 (recursive?dest+base+"/":dest),filemask);
215 }
216 else tmp=({});
217 //DEBUG("DEPTH: " + depth + " : " + sizeof(pathmask));
218 if((!filemask&&(depth==sizeof(pathmask)))||
219 (filemask&&(depth+2>sizeof(pathmask))&&
220 sizeof(regexp(({ base }),filemask,RE_TRADITIONAL)))||
221 ((mode==MODE_CP||mode==MODE_MV||(filemask&&
222 (mode==MODE_RM)&&sizeof(regexp(({ base}),filemask,RE_TRADITIONAL))))&&
223 sizeof(tmp)))
224 {
225 //DEBUG("ADDING: " + base+ " : "+ full );
226 files+=({ data[0..2]+({ full, path, dest+base,sizeof(tmp)}) });
227 }
228 if (sizeof(files)+sizeof(tmp)>MAX_ARRAY_SIZE)
229 raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
230 files+=tmp;
231 data=data[3..];
232 }
233 if(sizeof(files)>300&&!IS_ARCH(this_object()))
234 // Tod allen Laggern!
235 raise_error("Zu viele Files (>300)!! Abgebrochen!\n");
236 return files;
237}
238
239
240//
241// get_files: Basisroutine zum Ermitteln der zu bearbeitenden Dateien
242// filename: Pfadmaske, Verzeichnisname, Dateiname, der bearbeitet werden
243// soll
244// mode: Welche Daten werden benoetigt? (siehe magier.h)
245// recursive: Auch Unterverzeichnisse bearbeiten?
246// dest: Wenn kopiert werden soll: wohin?
247// filemask: Maske, der die Dateinamen genuegen muessen
248// Rueckgabe: Alist mit den Dateiinformationen
249//
250
251static varargs mixed *get_files(string filename, int mode, int recursive, string dest, string filemask)
252{
253 string full,path,base,*patharray,*vrooms,dest2;
254 object vcompiler;
255 mixed *files,*data;
256
257 // DEBUG("GF: " + filename);
258 // DEBUG("REC: " + recursive + " MODE: " + mode);
259 // if (dest[<1..<1]!="/") DEBUG("DEST: " + dest);
260 if (filename=="/")
261 {
262 switch (mode)
263 {
264 case MODE_LSA: return ({({ "", -2, 0,"","","",0 })});
265 default: if (!recursive) return ({});
266 break;
267 }
268 }
269 patharray=explode(filename,"/");
270 if(!sizeof(data=get_dir(filename,7)||({}))&&
271 (mode==MODE_UPD||mode==MODE_MORE||mode==MODE_ED))
272 data=get_dir(filename+".c",7)||({});
273 if ((mode==MODE_LSA||mode==MODE_LSB)&&
274 (vcompiler = find_object(implode(patharray[0..<2],"/")+"/virtual_compiler")) &&
275 pointerp(vrooms=(mixed *)vcompiler->QueryObjects()))
276 map(vrooms,#'_vc_map,&data);
277 files=({});
278 if (sizeof(data)) // passende files
279 {
280 mixed *subfiles;
281 subfiles=({});
282 path=implode(patharray[0..<2],"/")+"/";
283 while (sizeof(data))
284 {
285 subfiles=({});
286 base=data[BASENAME];
287 if (mode==MODE_LSB||(base!="."&&base!=".."))
288 {
289 //DEBUG("PATH: " + path+" BASE: " + base + " MODE: " + mode);
290 full=path+base;
291 dest2=((dest=="/"||file_size(dest[0..<2])==-2)?
292 (dest+base):(dest=="/"?"/":dest[0..<2]));
293 //DEBUG("DEST: " + dest);
294 if (recursive&&data[FILESIZE]==-2) // Verzeichnis, Rekursiv
295 subfiles=_get_files(full+"/",filemask,mode,dest2+"/");
296 if (!(filemask&&!sizeof(subfiles)&&!sizeof(regexp(({ base }),filemask,RE_TRADITIONAL))))
297 {
298 if (!filemask||mode!=MODE_RM)
299 files+=({ data[0..2]+({ full, path, dest2,sizeof(subfiles)}) });
300 if (sizeof(files)+sizeof(subfiles)>MAX_ARRAY_SIZE)
301 raise_error("Zu viele Files (>3000)!! Abgebrochen!\n");
302 files+=subfiles;
303 }
304 }
305 data=data[3..];
306 }
307 return files;
308 }
309// File existiert nicht -> Wildcard oder tatsaechlich nicht existent
310// Behandeln je nach mode
311 switch(mode)
312 {
313 case MODE_CP:
314 case MODE_MV:
315 case MODE_CD:
316 case MODE_LSA:
317 files=_get_matching(patharray+(filemask?({ "*" }):({})),1,"/",mode,
318 recursive,dest,filemask);
319 break;
320 default: break;
321 }
322 return files;
323}
324
325
326//
327// file_list(): Liste der Fileinformationen
328// files: Array der Filenamen MIT Wildcards
329// mode: Welche Daten werden benoetigt
330// recursive: Rekursiv listen?
331// dest: Zielverzeichnis
332// mask: Maske (regexp, wenn definiert)
333// Rueckgabe: Liste der betroffenen Files
334//
335
336static varargs mixed *file_list(string *files, int mode, int recursive, string dest, string mask)
337{
338 string *list,err,*result;
339 int i,j;
340 list=({});
341 if (mask) mask=glob2regexp(mask);
342 j=sizeof(files);
343 for(i=0;i<j;i++)
344 {
345 // Abschliessenden / von Pfadnamen abschneiden, weil in diesem Fall
346 // die Inhalte der ersten Unterverzeichnisebene mit ausgegeben
347 // wurden. Ursache hierfuer ist ein Fix an full_path_array() im
348 // Masterobjekt, der dazu fuehrte, dass get_dir() den abschliessenden /
349 // des uebergebenen Pfades jetzt korrekt behandelt. \o/
350 if ( sizeof(files[i]) > 1 && files[i][<1] == '/' )
351 {
352 files[i] = files[i][0..<2];
353 if ( !sizeof(files[i]) )
354 continue;
355 }
356 if (err=catch(list+=get_files(files[i],mode,recursive,dest,mask)))
357 {
358 printf("Fehler aufgetreten: %s\n",err);
359 log_file(SHELLLOG("FILE_LIST"),
360 sprintf("%s fuehrte folgendes Kommando aus: (Zeit: %s)\n"
361 " >>%s %s<<\n"
362 " Folgender Fehler trat dabei auf:\n"
363 " %s\n\n",
364 capitalize(getuid())||"<Unbekannt>",dtime(time()),
365 query_verb()||"*",_unparsed_args()||"*",err||"*"));
366 return ({});
367 }
368 }
369 return list;
370}