blob: 74821564967a59eb2c8e47d4b38627d445db1132 [file] [log] [blame]
// MorgenGrauen MUDlib
//
// upd.c
//
// $Id: upd.c 8850 2014-06-13 21:34:44Z Zesstra $
#pragma strict_types
#pragma save_types
#pragma range_check
#pragma no_clone
#define NEED_PROTOTYPES
#include <magier.h>
#include <player.h>
#undef NEED_PROTOTYPES
#include <debug_info.h>
#include <wizlevels.h>
#include <moving.h>
#include <properties.h>
#include <logging.h>
#include <thing/properties.h>
varargs static int _make(string file, int flags, int recursive);
static mixed _query_localcmds()
{
return ({({"upd","_upd",0,LEARNER_LVL}),
({"load","_load",0,LEARNER_LVL})});
}
//
// _save(): Spieler in Rettungsraum retten
// obj: Spielerobjekt(?)
// inv_save: Rettungsraumname
// Rueckgabe: 0 wenn kein Spielerobjekt
// Spielerobjekt, falls doch
//
static mixed _save( object obj, object inv_saver )
{
if ( query_once_interactive(obj) )
{
({int})obj->move( inv_saver, NO_CHECK );
return obj;
}
return 0;
}
//
// _reload(): Objekt laden
// file: Filename. Muss in der Form /xx/xx/xx.c vorliegen
// clone: > 0 -> Es soll geclont werden, enthaelt Objektnummer des
// Vorgaengerobjektes
// flags: Kommandozeilenoptionen
// err: Leerstring als Referenz uebergeben. Enthaelt nach dem
// Aufruf vom _reload() die Fehlermeldungen als String.
// Rueckgabe: Das neu erzeugte Objekt bzw. das schon vorhandene Objekt
// bzw. 0, wenn Fehler auftrat.
//
private object _reload(string file, int clone, int flags, string err)
{
object obj;
if (!obj=find_object(file[0..<3]+(clone?("#"+clone):"")))
{
int pos,pos2;
if(file_size(file)<0)
{
if (file_size(file)==-1)
err = sprintf("upd: %s: Datei existiert nicht.\n", file);
else // directory
err = sprintf("upd: %s: Verzeichnisse koennen nicht geladen "
"werden.\n",file);
return obj; // 0
}
pos = max(file_size(__DEBUG_LOG__),0);
if ((err = (clone?catch(obj = clone_object(file)):
catch(load_object(file)) )) && (flags & UPD_B))
{
if (( pos2=file_size(__DEBUG_LOG__)) > pos )
err+=sprintf("\nBacktrace:\n%s",
read_bytes(__DEBUG_LOG__,pos, pos2-pos ));
else
err+=sprintf("\nKEIN BACKTRACE VERFUEGBAR!\n");
}
if (!err&&!obj&&(!obj = find_object(file[0..<3])))
err += sprintf( "upd: %s: Blueprint nach dem Laden zerstoert.\n",file );
}
else
err=sprintf("upd: Objekt existiert schon: %O\n",obj);
return obj;
}
//
// _update(): File updaten -> Blueprint destructen
// file: Filename
// dummy: simulieren? (1->wird nicht aktualisiert)
// flags: Kommandozeilenoptionen
// Rueckgabe: -1: Keine Vollzugriff
// 0: Objekt ist nicht geladen
// 1: Operation wird durchgefuehrt
//
private varargs int _update(string file, int dummy, int flags)
{
object obj;
string err;
if (!dummy && !objectp(obj = find_object(file))) return 0;
if (!IS_ARCH(this_object()))
{
// Schreibrechte nur pruefen, wenn echt aktualisiert werden soll.
if(!dummy && !MAY_WRITE(file))
return (printf("upd: %s: Keine Schreibrechte!\n",file), -1);
if(!MAY_READ(file))
return (printf("upd: %s: Keine Leserechte!\n", file), -1);
}
if (dummy) return 1;
if ( flags & UPD_D )
{
object *inv;
if (sizeof(inv = deep_inventory(obj)))
{
printf("upd: %s: Entferne Objekte im Inventar\n", file );
if (!(flags&UPD_H))
{
if(err=catch(filter_objects( inv, "remove", 1 )))
printf("upd: %s: Fehlgeschlagen. Grund:\n%s\n",
file,err);
}
if (sizeof(inv = deep_inventory(obj)))
filter(inv, function void (object ob)
{destruct(ob);});
}
}
if (!(flags&UPD_H))
{
if(err = catch(({int})obj->remove()))
printf("upd: %s: remove() fehlgeschlagen. Aufruf von " +
"destruct().\n",file);
}
if(objectp(obj)) destruct(obj);
return 1;
}
//
// _instance_upd(): Alle Objekte nach Clones des Objekts durchsuchen
// file: Filename des Objektes
// flags: Kommandozeilenargumente
// obj: Aktuelles Objekt
// instances: Zahl der gefundenen Instanzen
//
private void _instance_upd(string file, int flags, mixed obj, int instances,
int firstcall)
{
int i;
if (firstcall)
printf("upd: %s: %s Instanzen.\n",file,flags&UPD_A?"Aktualisiere":"Suche");
while (get_eval_cost()>220000 && i < sizeof(obj))
{
if (!objectp(obj[i]))
instances--;
else
{
if (flags&UPD_F&&!(flags&UPD_S))
printf( "upd: %O gefunden in %s\n", obj[i],
environment(obj[i])?object_name(environment(obj[i]))
: "keiner Umgebung" );
if (flags&UPD_A) _make(object_name(obj[i]), flags & ~(UPD_A|UPD_F),1 );
}
i++;
}
if (i < sizeof(obj))
call_out( #'_instance_upd/*'*/,2,file,flags,obj[i..],instances,0);
else
printf( "upd: %s: %d Instanzen %s\n", file, instances,
(flags & UPD_A) ? "aktualisiert" : "gefunden" );
return;
}
//
// _do_make(): Alle geerbten Objekte bearbeiten (fuer -m/-v)
// file: Name des Files
// clone: 0, wenn blueprint, ansonsten Clonenummer
// flags: Kommandozeilenparameter
// dep: geschachteltes Array mit Meldungen (wg. Rekursion)
// ready: Array der schon bearbeiteten Objekte (wg. Rekursion)
// Rueckgabe: Array der Objektnamen, die bearbeitet wurden
// (Array in Array in ...)
//
varargs private int _do_make( string file,int clone,int flags,mixed dep,
string *ready )
{
object obj;
string err;
string *ilist;
mixed downdeps;
int ret;
if (!pointerp(ready)) ready = ({});
ready += ({ file });
if ( !(obj = _reload(file,clone,flags,&err)))
{
dep += ({ err });
return 0;
}
ilist = inherit_list(obj)-ready;
downdeps = ({});
while (sizeof(ilist))
{
ret = _do_make( ilist[0],0,flags, &downdeps, &ready )||ret;
ilist[0..0] = ({});
ilist -= ready;
}
if ( ret||file_time(file)>program_time(obj)||(flags &UPD_I))
if ( _make( file, flags & ~(UPD_M|UPD_I) ,1) < 0 )
dep = ({ "{" + explode(file,"/")[<1] + "}", downdeps });
else{
dep = ({ "[" + explode(file,"/")[<1] + "]", downdeps });
ret = 1;
}
else if (flags&UPD_V) dep += ({ explode(file,"/")[<1], downdeps });
return ret;
}
//
// _make_dep(): Ausgabe des Ererbungsbaumes
// Objekte im Array dep
// prefix enthaelt Zeilenanfang (fuer Rekursion)
// Rueckgabe: String mit dem Vererbungsbaum des Objektes
//
private string _make_dep( mixed dep, string prefix )
{
string ret;
int i, size;
ret="";
size=sizeof(dep);
for (i=0; i<size;i++)
if (pointerp(dep[i]))
ret += _make_dep(dep[i],prefix + (i < (size-1) ? "| ":" "));
else
ret += prefix + "+-" + dep[i] + "\n";
return ret;
}
//
// _make(): Update file
// file: Filename
// flags: Kommandozeilenargumente
//
varargs static int _make(string file, int flags,int recursive)
{
string msg, err, blue;
int inst;
object obj, inv_saver;
mixed tmp;
msg = "";
if (!file) return printf( "upd: Kein Filename uebergeben!\n" ), RET_FAIL;
// Filename in Blue, Objektname in blue, Instanznummer in inst
if (sscanf(file,"%s#%d",blue,inst)==2) blue += ".c";
else blue = file + (file[<2..]==".c" ? "" : ".c");
// Alle Instanzen durchsuchen im Falle von -a oder -f
if ((flags & UPD_LOAD)&&find_object(file))
return printf("load: %s: Objekt ist schon geladen.\n",file),RET_OK;
if ( flags & (UPD_F|UPD_A))
{
if (inst) return printf( "upd: %s: Eine Instanz kann keine " +
"Clones haben.\n",file ), RET_FAIL;
if ((tmp=_update(file, 1,flags))==-1)
return printf( "upd: %s: Kein Vollzugriff auf die " +
"Datei erlaubt.\n",file), RET_FAIL;
if (tmp==0) return RET_FAIL;
tmp=clones(blue[0..<3],2);
if (sizeof(tmp))
call_out( #'_instance_upd/*'*/, 0, file,flags,tmp,sizeof(tmp),1);
else
printf( "upd: %s: Keine Clones vorhanden!\n", blue[0..<3]);
if ( (flags & UPD_F) && !(flags &(UPD_R|UPD_L|UPD_LOAD))) return RET_OK;
// Nichts laden -> Auch kein Backup
}
// Backupraum festlegen
if( blue==INV_SAVE ) {
printf("upd: Achtung: Raum zum Zwischenspeichern soll geladen werden?!\n");
}
if ( !(inv_saver=load_object(INV_SAVE)) )
{
printf("upd: %s: Raum zum Zwischenspeichern des " +
"Rauminhalts ist nicht ladbar.\n" +
" %s\n",file,INV_SAVE);
return RET_FAIL;
}
// Wenn das Objekt existiert bzw. Deep aktualisiert werden soll
if ( (!(flags&UPD_LOAD))&&
((obj = find_object(file)) || (flags & (UPD_M|UPD_I))))
{
object *inv, env;
mapping pro;
int i;
mixed configdata;
int restore_config;
// Wenn Objekt existiert, dann Inhalt und ggf. Daten aus Configure() sichern
if (obj)
{
catch(restore_config=call_resolved(&configdata,obj,
"Configure",0);
publish);
// Wenn UPD_CONF gesetzt wird, _muss_ das Objekt ein oeffentliches
// Configure() definieren, sonst erfolgt Abbruch.
if ((flags & UPD_CONF) && !restore_config)
{
printf("upd: %s: hat kein Configure(), Zerstoerung abgebrochen.\n",file);
return RET_FAIL;
}
if (!(flags&UPD_D)&&(flags&(UPD_L|UPD_R)))
{
if (i=sizeof(inv=(all_inventory(obj)-({0}))))
{
mixed items;
// Herausbekommen, ob hier Items existieren, die per AddItem
// erzeugt werden. Die duerfen nicht gesichert werden.
items=({mixed})obj->QueryProp(P_ITEMS); // mixed, da array of arrays
if (pointerp(items)&&sizeof(items))
{
items=transpose_array(items)[0];
while (i--)
if (member(items, inv[i])==-1)
({int})inv[i]->move(inv_saver,NO_CHECK);
}
else // In diesem Objekt sind keine Items gesetzt.
while (i--) ({int})inv[i]->move(inv_saver,NO_CHECK);
}
}
else
{
inv=map( deep_inventory(obj), #'_save/*'*/, inv_saver )-({0});
}
env = environment(obj);
}
else inv = ({});
// Ererbte Objekte durchsuchen.
if ( flags & (UPD_M|UPD_I) )
{
mixed dep;
dep = ({});
_do_make( blue, inst, flags & ~(UPD_M|UPD_L|UPD_R|UPD_F|UPD_A), &dep );
printf( _make_dep( dep, "" ) + "\n" );
}
// Tatsaechlichen Update durchfuehren
if ( _update(file, 0, flags)< 0) return RET_FAIL;
msg += (inst ? "zerstoert" : "aktualisiert");
// Neu laden ??
if ( flags & (UPD_R|UPD_L) )
{
if ( obj = _reload( blue,inst,flags, &err ) )
msg += ", " + (inst ? "neu geclont" : "neu geladen");
// Neu geladen: Konfiguration wiederherstellen
if (!err)
{
if (!obj) obj = find_object(file);
// Ggf. Ergebnis von Configure() uebergeben
if (restore_config)
{
int conf_res;
if (!catch(conf_res=({int})obj->Configure(configdata); publish)
&& conf_res == 1)
{
msg += ", (re-)konfiguriert";
}
else
{
msg += ", (Re-)Konfiguration fehlgeschlagen";
if (flags & UPD_CONF)
printf("upd: Daten von %s konnten nicht rekonfiguriert werden: "
"%O\n", file, configdata);
}
}
if (env)
{
if ( ({int})obj->move( env, NO_CHECK ) <= 0 )
printf( "upd: /%O konnte nicht in /%O zurueckbewegt werden\n",
obj, env );
else
msg += ", bewegt";
}
if (i=sizeof(inv))
{
while(i--) if (inv[i]) ({int})inv[i]->move(obj, NO_CHECK );
msg += ", Inhalt zurueckbewegt";
}
}
else
return printf( "upd: %s: %s", file, err ), RET_FAIL;
}
}
else
if ( !_update(file, 0, flags) && (flags & (UPD_L|UPD_LOAD)) )
if ( !_reload( blue, inst, flags, &err ) )
return printf( "%s: %s: %s", (flags&UPD_LOAD?"load":"upd"),file, err ),
RET_FAIL;
else
msg += "geladen";
if ( sizeof(msg)&&!(flags&UPD_S&&recursive) )
printf("%s: %s: %s.\n",(flags&UPD_LOAD?"load":"upd"),file,msg);
return RET_OK;
}
//
// _upd: Objekte laden, zerstoeren und aktualisieren
//
static int _upd(string cmdline)
{
int flags;
mixed *args;
cmdline=_unparsed_args();
args=parseargs(cmdline,&flags,UPD_OPTS,1);
if(flags==-1||!sizeof(args))
return USAGE("upd [-"+UPD_OPTS+"] <datei> [<datei> ..]");
args=file_list(args,MODE_UPD,0,"/");
if(!sizeof(args)) return printf("upd: Keine passende Datei gefunden!\n"),1;
args=map(args,(: $1[FULLNAME] :))-({0});
if(!sizeof(args))
{
printf("upd: Verzeichnisse koennen nicht aktualisiert werden!\n");
return 1;
}
asynchron(args,#'_make,flags,0,0);
return 1;
}
//
// _load: Objekte laden
//
static int _load(string cmdline)
{
int flags;
mixed *args;
cmdline=_unparsed_args();
args=parseargs(cmdline,&flags,"",1);
if(flags==-1||!sizeof(args))
return USAGE("load <datei> [<datei> ..]");
args=file_list(args,MODE_UPD,0,"/");
if(!sizeof(args)) return printf("load: Keine passende Datei gefunden!\n"),1;
args=map(args,(: (($1[FILESIZE]!=-2||find_object($1[FULLNAME]))?
$1[FULLNAME]:0) :))-({0});
if(!sizeof(args))
return printf("load: Verzeichnisse koennen nicht geladen werden!\n"),1;
asynchron(args,#'_make,UPD_LOAD,0,0);
return 1;
}