blob: f09ea9a50e584b4e1cf93114e2b485c84ae543bc [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// upd.c
4//
5// $Id: upd.c 8850 2014-06-13 21:34:44Z Zesstra $
6#pragma strict_types
7#pragma save_types
8#pragma range_check
9#pragma no_clone
10#pragma pedantic
11
12#define NEED_PROTOTYPES
13#include <magier.h>
14#include <player.h>
15#undef NEED_PROTOTYPES
16#include <debug_info.h>
17#include <wizlevels.h>
18#include <moving.h>
19#include <properties.h>
20#include <logging.h>
21#include <thing/properties.h>
22
23varargs static int _make(string file, int flags, int recursive);
24
25static mixed _query_localcmds()
26{
27 return ({({"upd","_upd",0,LEARNER_LVL}),
28 ({"load","_load",0,LEARNER_LVL})});
29}
30
31//
32// _save(): Spieler in Rettungsraum retten
33// obj: Spielerobjekt(?)
34// inv_save: Rettungsraumname
35// Rueckgabe: 0 wenn kein Spielerobjekt
36// Spielerobjekt, falls doch
37//
38
39static mixed _save( object obj, object inv_saver )
40{
41 if ( query_once_interactive(obj) )
42 {
43 obj->move( inv_saver, NO_CHECK );
44 return obj;
45 }
46 return 0;
47}
48
49
50//
51// _reload(): Objekt laden
52// file: Filename. Muss in der Form /xx/xx/xx.c vorliegen
53// clone: > 0 -> Es soll geclont werden, enthaelt Objektnummer des
54// Vorgaengerobjektes
55// flags: Kommandozeilenoptionen
56// err: Leerstring als Referenz uebergeben. Enthaelt nach dem
57// Aufruf vom _reload() die Fehlermeldungen als String.
58// Rueckgabe: Das neu erzeugte Objekt bzw. das schon vorhandene Objekt
59// bzw. 0, wenn Fehler auftrat.
60//
61
62private object _reload(string file, int clone, int flags, string err)
63{
64 object obj;
65
66 if (!obj=find_object(file[0..<3]+(clone?("#"+clone):"")))
67 {
68 int pos,pos2;
69 string bt;
70
71 if(file_size(file)<0)
72 {
73 if (file_size(file)==-1)
74 err = sprintf("upd: %s: Datei existiert nicht.\n", file);
75 else // directory
76 err = sprintf("upd: %s: Verzeichnisse koennen nicht geladen "
77 "werden.\n",file);
78 return obj; // 0
79 }
80 pos = max(file_size(__DEBUG_LOG__),0);
81
82 if ((err = (clone?catch(obj = clone_object(file)):
83 catch(load_object(file)) )) && (flags & UPD_B))
84 {
85 if (( pos2=file_size(__DEBUG_LOG__)) > pos )
86 err+=sprintf("\nBacktrace:\n%s",
87 read_bytes(__DEBUG_LOG__,pos, pos2-pos ));
88 else
89 err+=sprintf("\nKEIN BACKTRACE VERFUEGBAR!\n");
90 }
91 if (!err&&!obj&&(!obj = find_object(file[0..<3])))
92 err += sprintf( "upd: %s: Blueprint nach dem Laden zerstoert.\n",file );
93 }
94 else
95 err=sprintf("upd: Objekt existiert schon: %O\n",obj);
96 return obj;
97}
98
99
100//
101// _update(): File updaten -> Blueprint destructen
102// file: Filename
103// dummy: simulieren? (1->wird nicht aktualisiert)
104// flags: Kommandozeilenoptionen
105// Rueckgabe: -1: Keine Vollzugriff
106// 0: Objekt ist nicht geladen
107// 1: Operation wird durchgefuehrt
108//
109
110private varargs int _update(string file, int dummy, int flags)
111{
112 object obj;
113 string err;
114 if (!dummy && !objectp(obj = find_object(file))) return 0;
115 if (!IS_ARCH(this_object()))
116 {
117 // Schreibrechte nur pruefen, wenn echt aktualisiert werden soll.
118 if(!dummy && !MAY_WRITE(file))
119 return (printf("upd: %s: Keine Schreibrechte!\n",file), -1);
120 if(!MAY_READ(file))
121 return (printf("upd: %s: Keine Leserechte!\n", file), -1);
122 }
123 if (dummy) return 1;
124
125 if ( flags & UPD_D )
126 {
127 object *inv;
128 if (sizeof(inv = deep_inventory(obj)))
129 {
130 printf("upd: %s: Entferne Objekte im Inventar\n", file );
131 if (!(flags&UPD_H))
132 {
133 if(err=catch(filter_objects( inv, "remove", 1 )))
134 printf("upd: %s: Fehlgeschlagen. Grund:\n%s\n",
135 file,err);
136 }
137 if (sizeof(inv = deep_inventory(obj)))
138 filter(inv, function void (object ob)
139 {destruct(ob);});
140 }
141 }
142 if (!(flags&UPD_H))
143 {
144 if(err = catch(obj->remove()))
145 printf("upd: %s: remove() fehlgeschlagen. Aufruf von " +
146 "destruct().\n",file);
147 }
148 if(objectp(obj)) destruct(obj);
149 return 1;
150}
151
152
153//
154// _instance_upd(): Alle Objekte nach Clones des Objekts durchsuchen
155// file: Filename des Objektes
156// flags: Kommandozeilenargumente
157// obj: Aktuelles Objekt
158// instances: Zahl der gefundenen Instanzen
159//
160
161private void _instance_upd(string file, int flags, mixed obj, int instances,
162 int firstcall)
163{
164 int i;
165 if (firstcall)
166 printf("upd: %s: %s Instanzen.\n",file,flags&UPD_A?"Aktualisiere":"Suche");
167
168 while (get_eval_cost()>220000 && i < sizeof(obj))
169 {
170 if (!objectp(obj[i]))
171 instances--;
172 else
173 {
174 if (flags&UPD_F&&!(flags&UPD_S))
175 printf( "upd: %O gefunden in %s\n", obj[i],
176 environment(obj[i])?object_name(environment(obj[i]))
177 : "keiner Umgebung" );
178 if (flags&UPD_A) _make(object_name(obj[i]), flags & ~(UPD_A|UPD_F),1 );
179 }
180 i++;
181 }
182 if (i < sizeof(obj))
183 call_out( #'_instance_upd/*'*/,2,file,flags,obj[i..],instances,0);
184 else
185 printf( "upd: %s: %d Instanzen %s\n", file, instances,
186 (flags & UPD_A) ? "aktualisiert" : "gefunden" );
187 return;
188}
189
190
191//
192// _do_make(): Alle geerbten Objekte bearbeiten (fuer -m/-v)
193// file: Name des Files
194// clone: 0, wenn blueprint, ansonsten Clonenummer
195// flags: Kommandozeilenparameter
196// dep: geschachteltes Array mit Meldungen (wg. Rekursion)
197// ready: Array der schon bearbeiteten Objekte (wg. Rekursion)
198// Rueckgabe: Array der Objektnamen, die bearbeitet wurden
199// (Array in Array in ...)
200//
201
202varargs private int _do_make( string file,int clone,int flags,mixed dep,
203 string *ready )
204{
205 object obj;
206 string err;
207 string *ilist;
208 mixed downdeps;
209 int ret;
210
211 if (!pointerp(ready)) ready = ({});
212 ready += ({ file });
213
214 if ( !(obj = _reload(file,clone,flags,&err)))
215 {
216 dep += ({ err });
217 return 0;
218 }
219
220 ilist = inherit_list(obj)-ready;
221
222 downdeps = ({});
223
224 while (sizeof(ilist))
225 {
226 ret = _do_make( ilist[0],0,flags, &downdeps, &ready )||ret;
227 ilist[0..0] = ({});
228 ilist -= ready;
229 }
230
231 if ( ret||file_time(file)>program_time(obj)||(flags &UPD_I))
232 if ( _make( file, flags & ~(UPD_M|UPD_I) ,1) < 0 )
233 dep = ({ "{" + explode(file,"/")[<1] + "}", downdeps });
234 else{
235 dep = ({ "[" + explode(file,"/")[<1] + "]", downdeps });
236 ret = 1;
237 }
238 else if (flags&UPD_V) dep += ({ explode(file,"/")[<1], downdeps });
239 return ret;
240}
241
242
243//
244// _make_dep(): Ausgabe des Ererbungsbaumes
245// Objekte im Array dep
246// prefix enthaelt Zeilenanfang (fuer Rekursion)
247// Rueckgabe: String mit dem Vererbungsbaum des Objektes
248//
249
250private string _make_dep( mixed dep, string prefix )
251{
252 string ret;
253 int i, size;
254
255 ret="";
256 size=sizeof(dep);
257 for (i=0; i<size;i++)
258 if (pointerp(dep[i]))
259 ret += _make_dep(dep[i],prefix + (i < (size-1) ? "| ":" "));
260 else
261 ret += prefix + "+-" + dep[i] + "\n";
262 return ret;
263}
264
265
266//
267// _illegal_closure(): ist closure in arg an objekt gebunden?
268// arg: closure(-array/mapping)
269// Rueckgabe: 0 wenn alles okay
270// 1 wenn closure geloescht werden muss
271//
272
273private int _illegal_closure( mixed arg )
274{
275 int i, j;
276 string *indices;
277
278 if ( closurep(arg) && !objectp(query_closure_object(arg)) )
279 return 1;
280
281 if ( pointerp(arg) ){
282 for ( i = sizeof(arg); i--; )
283 if ( _illegal_closure(arg[i]) )
284 return 1;
285 }
286 else if ( mappingp(arg) ){
287 indices = m_indices(arg);
288 for ( i = sizeof(indices); i--; )
289 for ( j = get_type_info( arg, 1 ); j--; )
290 if ( _illegal_closure(arg[indices[i], j]) )
291 return 1;
292 }
293 return 0;
294}
295
296//
297// _make(): Update file
298// file: Filename
299// flags: Kommandozeilenargumente
300//
301
302varargs static int _make(string file, int flags,int recursive)
303{
304 string msg, err, blue;
305 int inst;
306 object obj, inv_saver;
307 mixed tmp;
308
309 msg = "";
310
311 if (!file) return printf( "upd: Kein Filename uebergeben!\n" ), RET_FAIL;
312
313// Filename in Blue, Objektname in blue, Instanznummer in inst
314
315 if (sscanf(file,"%s#%d",blue,inst)==2) blue += ".c";
316 else blue = file + (file[<2..]==".c" ? "" : ".c");
317
318// Alle Instanzen durchsuchen im Falle von -a oder -f
319
320 if ((flags & UPD_LOAD)&&find_object(file))
321 return printf("load: %s: Objekt ist schon geladen.\n",file),RET_OK;
322
323 if ( flags & (UPD_F|UPD_A))
324 {
325 if (inst) return printf( "upd: %s: Eine Instanz kann keine " +
326 "Clones haben.\n",file ), RET_FAIL;
327 if ((tmp=_update(file, 1,flags))==-1)
328 return printf( "upd: %s: Kein Vollzugriff auf die " +
329 "Datei erlaubt.\n",file), RET_FAIL;
330 if (tmp==0) return RET_FAIL;
331
332 tmp=clones(blue[0..<3],2);
333 if (sizeof(tmp))
334 call_out( #'_instance_upd/*'*/, 0, file,flags,tmp,sizeof(tmp),1);
335 else
336 printf( "upd: %s: Keine Clones vorhanden!\n", blue[0..<3]);
337
338 if ( (flags & UPD_F) && !(flags &(UPD_R|UPD_L|UPD_LOAD))) return RET_OK;
339 // Nichts laden -> Auch kein Backup
340 }
341
342// Backupraum festlegen
343
344 if( blue==INV_SAVE ) {
345 printf("upd: Achtung: Raum zum Zwischenspeichern soll geladen werden?!\n");
346 }
347 if ( !(inv_saver=load_object(INV_SAVE)) )
348 {
349 printf("upd: %s: Raum zum Zwischenspeichern des " +
350 "Rauminhalts ist nicht ladbar.\n" +
351 " %s\n",file,INV_SAVE);
352 return RET_FAIL;
353 }
354
355// Wenn das Objekt existiert bzw. Deep aktualisiert werden soll
356
357 if ( (!(flags&UPD_LOAD))&&
358 ((obj = find_object(file)) || (flags & (UPD_M|UPD_I))))
359 {
360 object *inv, env, *pl_inv;
361 mapping pro;
362 int i;
363 mixed configdata;
364 int restore_config;
365
366 // Wenn Objekt existiert, dann Inhalt und ggf. Daten aus Configure() oder
367 // Props sichern:
368 if (obj)
369 {
370 // im Fall UPD_C erfolgt _kein_ Auslesen und _keine_ Restauration
371 // mittels Configure()
372 if ( ! (flags & UPD_C ) )
373 {
374 catch(restore_config=(mixed)call_resolved(&configdata,obj,
375 "Configure",0);
376 publish);
377 // Wenn UPD_CONF gesetzt wird, _muss_ das Objekt ein oeffentliches
378 // Configure() definieren, sonst erfolgt Abbruch.
379 if ((flags & UPD_CONF) && !restore_config)
380 {
381 printf("upd: %s: hat kein Configure(), Zerstoerung abgebrochen.\n",file);
382 return RET_FAIL;
383 }
384 }
385 if (!(flags&UPD_D)&&(flags&(UPD_L|UPD_R)))
386 {
387 if (i=sizeof(inv=(all_inventory(obj)-({0}))))
388 {
389 mixed items;
390 // Herausbekommen, ob hier Items existieren, die per AddItem
391 // erzeugt werden. Die duerfen nicht gesichert werden.
392 items=(mixed)obj->QueryProp(P_ITEMS); // mixed, da array of arrays
393 if (pointerp(items)&&sizeof(items))
394 {
395 items=transpose_array(items)[0];
396 while (i--)
397 if (member(items, inv[i])==-1)
398 inv[i]->move(inv_saver,NO_CHECK);
399 }
400 else // In diesem Objekt sind keine Items gesetzt.
401 while (i--) inv[i]->move(inv_saver,NO_CHECK);
402 }
403 }
404 else
405 {
406 inv=map( deep_inventory(obj), #'_save/*'*/, inv_saver )-({0});
407 }
408 env = environment(obj);
409 if ( flags & UPD_C )
410 {
411 pro = (mapping)(obj->QueryProperties());
412 }
413 }
414 else inv = ({});
415
416// Ererbte Objekte durchsuchen.
417 if ( flags & (UPD_M|UPD_I) )
418 {
419 mixed dep;
420 dep = ({});
421 _do_make( blue, inst, flags & ~(UPD_M|UPD_L|UPD_R|UPD_F|UPD_A), &dep );
422 printf( _make_dep( dep, "" ) + "\n" );
423 }
424
425// Tatsaechlichen Update durchfuehren
426
427 if ( _update(file, 0, flags)< 0) return RET_FAIL;
428 msg += (inst ? "zerstoert" : "aktualisiert");
429
430// Neu laden ??
431 if ( flags & (UPD_R|UPD_L) )
432 {
433 if ( obj = _reload( blue,inst,flags, &err ) )
434 msg += ", " + (inst ? "neu geclont" : "neu geladen");
435
436// Neu geladen: Properties wiederherstellen, Closures filtern
437 if (!err)
438 {
439 if (!obj) obj = find_object(file);
440 // Wenn gewuenscht, Props zurueckschreiben (hat Prioritaet vor
441 // Configure(), weil explizit vom Magier angefordert).
442 if ( pro && (flags & UPD_C) )
443 {
444 string *names;
445
446 names = m_indices(pro);
447
448 // Closures in (mittlerweile) zerstoerten Objekten
449 // rausfiltern, damit die (hoffentlich korrekten) Closures
450 // im neu geclonten Objekt erhalten bleiben
451 for ( i = sizeof(names); i--; )
452 if ( _illegal_closure(pro[names[i], F_VALUE]) ||
453 _illegal_closure(pro[names[i], F_QUERY_METHOD]) ||
454 _illegal_closure(pro[names[i], F_SET_METHOD]) )
455 m_delete( pro, names[i] );
456
457 obj->SetProperties(pro);
458 msg += ", Properties gesetzt";
459 }
460 // Wenn kein UPD_C, wird ggf. das Ergebnis von Configure() wieder
461 // uebergeben.
462 else if (restore_config)
463 {
464 int conf_res;
465 if (!catch(conf_res=(int)obj->Configure(configdata); publish)
466 && conf_res == 1)
467 {
468 msg += ", (re-)konfiguriert";
469 }
470 else
471 {
472 msg += ", (Re-)Konfiguration fehlgeschlagen";
473 if (flags & UPD_CONF)
474 printf("upd: Daten von %s konnten nicht rekonfiguriert werden: "
475 "%O\n", file, configdata);
476 }
477 }
478 if (env)
479 {
480 if ( obj->move( env, NO_CHECK ) <= 0 )
481 printf( "upd: /%O konnte nicht in /%O zurueckbewegt werden\n",
482 obj, env );
483 else
484 msg += ", bewegt";
485 }
486 if (i=sizeof(inv))
487 {
488 while(i--) if (inv[i]) inv[i]->move(obj, NO_CHECK );
489 msg += ", Inhalt zurueckbewegt";
490 }
491 }
492 else
493 return printf( "upd: %s: %s", file, err ), RET_FAIL;
494 }
495 }
496 else
497 if ( !_update(file, 0, flags) && (flags & (UPD_L|UPD_LOAD)) )
498 if ( !_reload( blue, inst, flags, &err ) )
499 return printf( "%s: %s: %s", (flags&UPD_LOAD?"load":"upd"),file, err ),
500 RET_FAIL;
501 else
502 msg += "geladen";
503
504 if ( sizeof(msg)&&!(flags&UPD_S&&recursive) )
505 printf("%s: %s: %s.\n",(flags&UPD_LOAD?"load":"upd"),file,msg);
506 return RET_OK;
507}
508
509//
510// _upd: Objekte laden, zerstoeren und aktualisieren
511//
512
513static int _upd(string cmdline)
514{
515 int flags;
516 mixed *args;
517
518 cmdline=_unparsed_args();
519 args=parseargs(cmdline,&flags,UPD_OPTS,1);
520 if(flags==-1||!sizeof(args))
521 return USAGE("upd [-"+UPD_OPTS+"] <datei> [<datei> ..]");
522 if ((flags & UPD_C) && (flags & UPD_CONF))
523 {
524 printf("upd: -c und -C gleichzeitig werden nicht unterstuetzt.\n");
525 return 1;
526 }
527 args=file_list(args,MODE_UPD,0,"/");
528 if(!sizeof(args)) return printf("upd: Keine passende Datei gefunden!\n"),1;
529
530 args=map(args,(: $1[FULLNAME] :))-({0});
531
532 if(!sizeof(args))
533 {
534 printf("upd: Verzeichnisse koennen nicht aktualisiert werden!\n");
535 return 1;
536 }
537 asynchron(args,#'_make,flags,0,0);
538 return 1;
539}
540
541//
542// _load: Objekte laden
543//
544
545static int _load(string cmdline)
546{
547 int flags;
548 mixed *args;
549
550 cmdline=_unparsed_args();
551 args=parseargs(cmdline,&flags,"",1);
552 if(flags==-1||!sizeof(args))
553 return USAGE("load <datei> [<datei> ..]");
554 args=file_list(args,MODE_UPD,0,"/");
555 if(!sizeof(args)) return printf("load: Keine passende Datei gefunden!\n"),1;
556 args=map(args,(: (($1[FILESIZE]!=-2||find_object($1[FULLNAME]))?
557 $1[FULLNAME]:0) :))-({0});
558
559 if(!sizeof(args))
560 return printf("load: Verzeichnisse koennen nicht geladen werden!\n"),1;
561 asynchron(args,#'_make,UPD_LOAD,0,0);
562 return 1;
563}