campo-sirio/ba/ba1600.cpp

882 lines
22 KiB
C++
Raw Normal View History

#include <dos.h>
#include <applicat.h>
#include <execp.h>
#include <msksheet.h>
#include <progind.h>
#include <urldefid.h>
#include <utility.h>
#include "ba1.h"
#include "ba1600.h"
#include "ba1600a.h"
#define FOR_EACH_SHEET_ROW(__sheet, __r, __riga) TToken_string* __riga; for (int __r = 0; __r < __sheet.items() && (const char*)(__riga = &__sheet.row(__r)); __r++)
#define FOR_EACH_SHEET_ROW_BACK(__sheet, __r, __riga) TToken_string* __riga; for (int __r = __sheet.items()-1; __r >= 0 && (const char*)(__riga = &__sheet.row(__r)); __r--)
///////////////////////////////////////////////////////////
// Configurazione per installazione
///////////////////////////////////////////////////////////
int TInstall_ini::build_list(const TString& module, TString_array& a,
const char* sommario, bool agg)
{
CHECKS(module.len() >= 2, "Bad module ", (const char*)module);
TConfig* sum = NULL;
if (sommario)
sum = new TConfig(sommario, module);
TAuto_token_string tmp;
TString paragraph;
for (int sub = 0; ; sub++)
{
paragraph = module;
if (module[2] == '\0') // Ho specificato un modulo principale
paragraph << sub;
if (set_paragraph(paragraph))
{
for (int index = 0; exist("File", index); index++)
{
tmp = get("File", NULL, index); // Nome e aggiornamento
// Quando creo il disco di aggiornamento salto tutti i file
// che non hanno il flag di aggiornamento settato
if (agg && tmp.get_char(1) <= ' ')
continue;
if (sum)
sum->set("File", tmp, paragraph, TRUE, index);
tmp.add(paragraph, 2); // Sottomodulo
tmp.lower();
a.add(tmp);
}
}
else
break;
if (module[2] == '\0')
break;
}
if (sum)
delete sum;
return a.items();
}
int TInstall_ini::build_complete_list(const TString& module, TString_array& a,
const char* sommario, bool agg)
{
build_list(module, a, sommario, agg);
TAuto_token_string altri(get("Moduli", module));
TString submodule;
for (const char* mod = altri.get(0); mod; mod = altri.get())
{
submodule = mod;
copy_paragraph(submodule, sommario);
}
return a.items();
}
void TInstall_ini::copy_paragraph(const char* module, const char* summary)
{
TConfig sum(summary, module);
TAssoc_array& ass = (TAssoc_array&)list_variables(module);
ass.restart();
for (THash_object* ho = ass.get_hashobj(); ho; ho = ass.get_hashobj())
{
const char* key = ho->key();
const TString& str = (TString&)ho->obj();
sum.set(key, str);
}
}
void TInstall_ini::copy_module_paragraphs(const char* module, const char* summary)
{
TString mod;
for (int sub = -1; ; sub++)
{
mod = module;
if (sub >= 0) mod << sub;
if (set_paragraph(mod))
copy_paragraph(module, summary);
else
break;
}
}
///////////////////////////////////////////////////////////
// TAuto_token_string
///////////////////////////////////////////////////////////
TAuto_token_string& TAuto_token_string::create(const char* ts)
{
// Copia la stringa
set(ts);
// Calcola il separatore
for (const char* s = get_buffer(); *s; s++)
{
if (strchr("|;,!^&+", *s) != NULL)
{
separator(*s);
break;
}
}
return *this;
}
///////////////////////////////////////////////////////////
// Maschera modulo
///////////////////////////////////////////////////////////
class TModule_mask : public TMask
{
protected:
static bool sheet_notify(TSheet_field& sf, int row, KEY key);
static bool missing_notify(TSheet_field& sf, int row, KEY key);
static bool file_handler(TMask_field& f, KEY k);
static bool link_handler(TMask_field& f, KEY k);
static bool deselect_handler(TMask_field& f, KEY k);
bool find(const TString& name) const;
bool kill_missing(const char* name, bool update);
public:
void load(const char* module);
void save();
TModule_mask();
virtual ~TModule_mask() { }
};
// Cerca un file nello sheet principale
bool TModule_mask::find(const TString& name) const
{
TSheet_field& sf = sfield(F_SHEET);
FOR_EACH_SHEET_ROW_BACK(sf, r, row)
{
if (name.compare(row->get(0), -1, TRUE) == 0)
break;
}
return r >= 0;
}
// Toglie il file dallo sheet dei mancanti
bool TModule_mask::kill_missing(const char* name, bool update)
{
TSheet_field& miss = sfield(F_MISSING);
FOR_EACH_SHEET_ROW_BACK(miss, r, row)
{
if (row->compare(name, -1, TRUE) == 0)
{
miss.destroy(r, update);
break;
}
}
return r >= 0;
}
bool TModule_mask::sheet_notify(TSheet_field& sf, int r, KEY key)
{
bool ok = TRUE;
switch(key)
{
case K_TAB:
// Posso cancellare solo le righe abilitate
sf.sheet_mask().enable(DLG_DELREC, !sf.cell_disabled(r, 1));
break;
case K_ENTER:
{
TFilename mask = sf.row(r).get(0);
if (mask.find('*') >= 0 || mask.find('?') >= 0)
{
TString_array arr; list_files(mask, arr);
const int items = arr.items();
TString16 module;
module << sf.mask().get(F_MODULE) << '0';
if (items > 0)
{
TModule_mask& msk = (TModule_mask&)sf.mask();
TFilename start;
DIRECTORY dir; xvt_fsys_get_dir(&dir);
xvt_fsys_convert_dir_to_str(&dir, start.get_buffer(), start.size());
const int maxlen = start.len();
bool found = FALSE;
for (int i = 0; i < items; i++)
{
TString& file = arr.row(i);
if (file.compare(start, maxlen, TRUE) == 0)
file.ltrim(maxlen+1);
file.lower();
msk.kill_missing(file, FALSE);
if (!msk.find(file))
{
TToken_string& row = sf.row(found ? -1 : r);
row = file;
row.add(module);
found = TRUE;
}
}
// Se ne ho trovato almeno uno valido allora updato
if (found)
{
sf.force_update();
TSheet_field& miss = msk.sfield(F_MISSING);
miss.force_update();
}
}
else
ok = sf.error_box("Nessun file corrisponde a %s", mask.get_buffer());
}
}
break;
case K_DEL:
ok = !sf.cell_disabled(r, 1);
if (ok)
{
// Sposto la riga cancellata nello sheet a fianco
TSheet_field& miss = sf.mask().sfield(F_MISSING);
miss.row(-1) = sf.row(r).get(0);
miss.force_update();
}
break;
case K_CTRL+K_INS:
{
// Propongo il sottomodulo automaticamente in inserimento
TString16 module;
module << sf.mask().get(F_MODULE) << '0';
TToken_string& row = sf.row(r);
row.add(module, 1);
}
break;
default:
break;
}
return ok;
}
bool TModule_mask::missing_notify(TSheet_field& sf, int r, KEY key)
{
bool ok = TRUE;
if (key == K_INS)
{
// Sposto tutte le righe nello spreadsheet a fianco
TMask& mainmask = sf.mask();
TSheet_field& sheet = mainmask.sfield(F_SHEET);
FOR_EACH_SHEET_ROW(sf, idx, riga)
{
TToken_string& newrow = sheet.row(-1);
newrow = *riga;
TString16 submod = newrow.left(2);
submod << '0';
newrow.add(submod, 2);
}
sf.destroy();
sf.force_update();
sheet.force_update();
ok = FALSE;
}
return ok;
}
bool TModule_mask::file_handler(TMask_field& f, KEY k)
{
if (k == K_F9)
{
TFilename start;
DIRECTORY dir; xvt_fsys_get_dir(&dir);
xvt_fsys_convert_dir_to_str(&dir, start.get_buffer(), start.size());
FILE_SPEC fs;
xvt_fsys_get_dir(&fs.dir);
strcpy(fs.type, "");
strcpy(fs.name, "*.*");
strcpy(fs.creator, "SETUP");
FL_STATUS ok = xvt_dm_post_file_open(&fs, "Selezionare il file ...");
xvt_fsys_set_dir(&dir);
if (ok == FL_OK)
{
TFilename file;
xvt_fsys_convert_dir_to_str(&fs.dir, file.get_buffer(), file.size());
const int maxlen = start.len();
if (file.compare(start, maxlen, TRUE) == 0)
{
file.ltrim(maxlen+1);
file.add(fs.name);
file.ext(fs.type);
f.set(file);
k = K_TAB;
}
else
{
return f.error_box("Il file deve trovarsi nel perrcorso %s",
start.get_buffer());
}
}
}
if (k = K_TAB && f.focusdirty())
{
TModule_mask& msk = (TModule_mask&)f.mask().get_sheet()->mask();
msk.kill_missing(f.get(), TRUE);
}
return TRUE;
}
bool TModule_mask::link_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TMask& modmask = f.mask();
TSheet_field* sf = modmask.get_sheet();
TMask& mainmask = sf->mask();
TSheet_field& sheet = mainmask.sfield(F_SHEET);
TToken_string& newrow = sheet.row(-1);
newrow = modmask.get(101);
TString16 submod = newrow.left(2);
submod << '0';
newrow.add(submod);
if (modmask.is_running())
{
modmask.stop_run(K_ESC);
do_events();
}
sf->destroy(sf->selected());
sheet.force_update();
sf->force_update();
}
return TRUE;
}
bool TModule_mask::deselect_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TSheet_field& sheet = f.mask().sfield(F_SHEET);
FOR_EACH_SHEET_ROW_BACK(sheet, r, row)
row->add(" ", 1);
sheet.force_update();
}
return TRUE;
}
void TModule_mask::load(const char* module)
{
TWait_cursor hourglass;
set(F_MODULE, module);
TInstall_ini ini;
TSheet_field& s = sfield(F_SHEET);
ini.build_list(module, s.rows_array());
s.rows_array().sort();
TFilename mask;
mask << module << "*.*";
TSheet_field& miss = sfield(F_MISSING);
TString_array& arr = miss.rows_array();
list_files(mask, arr);
const char* bad_ext[] = { "bsc", "mak", "obj", "pdb", "rc",
"res", "sbr", "vcw", "wsp", NULL };
for (int index = arr.items()-1; index >= 0; index--)
{
mask = arr.row(index);
mask.lower();
const TString16 ext = mask.ext();
bool ok = TRUE;
for (int e = 0; bad_ext[e]; e++)
{
if (ext == bad_ext[e])
{
ok = FALSE;
break;
}
}
if (ok)
{
TString_array& sarr = s.rows_array();
for (int i = sarr.items()-1; i >= 0; i--)
{
if (mask.compare(sarr.row(i).get(0), -1, TRUE) == 0)
break;
}
ok = i < 0;
}
if (ok)
arr.row(index) = mask;
else
arr.destroy(index);
}
arr.sort();
}
void TModule_mask::save()
{
TWait_cursor hourglass;
TSheet_field& sheet = sfield(F_SHEET);
TInstall_ini ini;
int index;
const TString module = get(F_MODULE);
for (index = 0; ; index++)
{
TString16 sub; sub << module << index;
if (ini.set_paragraph(sub))
{
TAssoc_array& list = (TAssoc_array&)ini.list_variables();
list.destroy();
}
else
break;
}
TToken_string tmp;
index = 0;
for (int r = 0; r < sheet.items(); r++)
{
TToken_string& row = sheet.row(r);
TString16 sub = row.get(2);
if (isdigit(sub[0]) || sub.left(2) == module)
{
tmp = row.get(0); // Nome del file
const bool agg = *row.get() > ' ';
if (agg) tmp.add("X"); // Flag aggiornamento
ini.set("File", tmp, sub, TRUE, index++);
}
}
}
TModule_mask::TModule_mask()
: TMask("ba1600b")
{
set_handler(F_DESELECT, deselect_handler);
TSheet_field& s = sfield(F_SHEET);
s.set_notify(sheet_notify);
s.sheet_mask().set_handler(S_FILE, file_handler);
TSheet_field& miss = sfield(F_MISSING);
miss.set_notify(missing_notify);
miss.disable(); // Read-only sheet
miss.sheet_mask().set_handler(100, link_handler);
}
///////////////////////////////////////////////////////////
// Maschera principale
///////////////////////////////////////////////////////////
class TFascicolator_mask : public TMask
{
protected:
static bool list_handler(TMask_field& f, KEY k);
static bool save_handler(TMask_field& f, KEY k);
bool zip_file(const char* archive, const char* file) const;
int split_file(const TFilename& file, long size) const;
bool move_file(const TFilename& file, const char* dir) const;
bool zip_module(const TString& module, bool agg) const;
public:
void load();
void save();
TFascicolator_mask();
virtual ~TFascicolator_mask() { }
};
bool TFascicolator_mask::list_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
const TMask& m = f.mask();
const TString& module = m.get(S_MODULE);
TModule_mask mm;
mm.load(module);
if (mm.run() == K_ENTER)
mm.save();
}
return TRUE;
}
bool TFascicolator_mask::save_handler(TMask_field& f, KEY k)
{
if (k == K_SPACE)
{
TMask& m = f.mask();
const TString& module = m.get(S_MODULE);
{
TInstall_ini ini;
ini.set_paragraph(module);
ini.set("Versione", m.get(S_VERSION));
ini.set("Data", m.get(S_DATE));
ini.set("Moduli", m.get(S_EXTERN));
ini.set("PreProcess", m.get(S_PREPROCESS));
ini.set("PostProcess", m.get(S_POSTPROCESS));
}
const bool agg = f.dlg() == S_SAVEAGG;
TFascicolator_mask& fm = (TFascicolator_mask&)m.get_sheet()->mask();
fm.zip_module(module, agg);
}
return TRUE;
}
void TFascicolator_mask::load()
{
TWait_cursor hourglass;
TSheet_field& s = sfield(F_SHEET);
TString tmp;
TString_array modules;
TInstall_ini ini;
ini.list_paragraphs(modules);
set(F_DISKSIZE, ini.get("DiskSize"));
set(F_DISKPATH, ini.get("DiskPath"));
for (int m = modules.items()-1; m >= 0; m--)
{
const TString& module = modules.row(m);
if (module.len() == 2)
{
TToken_string& row = s.row(-1);
ini.set_paragraph(module);
row = ini.get("Descrizione");
row.add(module);
tmp = ini.get("Versione");
row.add(tmp);
tmp = ini.get("Data");
row.add(tmp);
tmp = ini.get("Moduli");
row.add(tmp);
tmp = ini.get("PreProcess");
row.add(tmp);
tmp = ini.get("PostProcess");
row.add(tmp);
}
}
s.rows_array().sort();
}
void TFascicolator_mask::save()
{
TSheet_field& s = sfield(F_SHEET);
TProgind pi(s.items(), "Salvataggio in corso...", FALSE, TRUE);
TInstall_ini ini;
ini.set("DiskSize", get(F_DISKSIZE));
ini.set("DiskPath", get(F_DISKPATH));
TString tmp;
for (int r = s.items()-1; r >= 0; r--)
{
pi.addstatus(1);
TToken_string& row = s.row(r);
tmp = row.get(1);
if (tmp.not_empty() && tmp != "xx")
{
ini.set_paragraph(tmp);
tmp = row.get(0);
ini.set("Descrizione", tmp);
tmp = row.get(2);
ini.set("Versione", tmp);
tmp = row.get();
ini.set("Data", tmp);
tmp = row.get();
ini.set("Moduli", tmp);
tmp = row.get();
ini.set("PreProcess", tmp);
tmp = row.get();
ini.set("PostProcess", tmp);
}
}
}
bool TFascicolator_mask::zip_file(const char* archive, const char* file) const
{
TWait_cursor hourglass;
TFilename cmd(120);
cmd << "zip.pif " << archive << ' ' << file;
TExternal_app app(cmd);
int err = app.run(FALSE, FALSE, FALSE, FALSE);
return err == 0;
}
bool TFascicolator_mask::move_file(const TFilename& file, const char* dir) const
{
TFilename dest(dir);
dest.add(file.name());
const long filesize = fsize(file);
bool space_ok = FALSE;
while (!space_ok)
{
int disk = 0;
if (dest[1] == ':')
{
const char letter = toupper(dest[0]);
disk = 'A' - letter + 1;
}
struct _diskfree_t drive;
_dos_getdiskfree(disk, &drive);
const unsigned requested_clusters = unsigned(filesize / drive.sectors_per_cluster / drive.bytes_per_sector) + 1;
space_ok = requested_clusters <= drive.avail_clusters;
if (!space_ok)
{
TString msg(128);
msg << "Lo spazio sull'unita' e' insufficiente";
if (disk == 1 || disk == 2)
{
msg << ":\nInserire un nuovo disco e ritentare?";
if (!yesno_box(msg))
return FALSE;
}
else
return error_box(msg);
}
}
bool write_ok = TRUE;
bool user_abort = FALSE;
do
{
write_ok = ::fcopy(file, dest);
if (write_ok)
::remove(file);
else
{
if (!yesno_box("Errore di scrittura del file %s.\nSi desidera riprovare?",
(const char*)file));
user_abort = TRUE;
}
} while (!write_ok && !user_abort);
return write_ok;
}
int TFascicolator_mask::split_file(const TFilename& archive, long size) const
{
TWait_cursor hourglass;
int disks = 1;
if (size > 0L)
{
TFilename sommario(archive); sommario.ext("ini");
size -= ::fsize(sommario);
const long minsize = 360*1024L;
if (size < minsize)
size = minsize;
DIRECTORY curdir, tmpdir;
xvt_fsys_get_dir(&curdir); // Legge directory corrente
// Costruisce percorso assoluto dello splitter
TFilename cmd;
xvt_fsys_convert_dir_to_str(&curdir, cmd.get_buffer(), cmd.size());
cmd.add("zipsplit.pif");
cmd << " -n " << size << " " << archive;
// Salta alla directory temporanea
xvt_fsys_convert_str_to_dir((char*)archive.path(), &tmpdir);
xvt_fsys_set_dir(&tmpdir);
// Esegue lo splitter nella directory temporanea
TExternal_app app(cmd);
int err = app.run(FALSE, FALSE, FALSE, FALSE);
// Torna nella directory principale
xvt_fsys_set_dir(&curdir);
if (err != NOERR)
return error_box("Errore %d durante lo splitting del file %s",
err, (const char*)archive);
// Conta il numero di dischetti generati
TFilename src;
for (int d = 2; ; d++)
{
src = archive;
src.ext("");
src << d;
src.ext("zip");
if (::fexist(src))
disks = d;
else
break;
}
::remove(archive);
}
return disks;
}
bool TFascicolator_mask::zip_module(const TString& main_module, bool agg) const
{
TString_array arr;
TInstall_ini ini;
TFilename sommario; sommario.tempdir();
sommario.add(main_module);
sommario << "inst.ini"; // Nome del file sommario completo
ini.build_complete_list(main_module, arr, sommario, agg);
if (arr.items() == 0)
{
::remove(sommario);
return error_box("Nessun file da compattare");
}
TFilename archivio(sommario);
archivio.ext("zip"); // Nome del file archivio completo
bool aborted = FALSE;
TString msg;
msg << "Creazione del file " << archivio << " ...";
TProgind pi(arr.items(), msg, TRUE, TRUE);
TFilename cmd;
for (int i = arr.items()-1; i >= 0; i--)
{
pi.addstatus(1);
if (pi.iscancelled())
{
aborted = TRUE;
break;
}
TToken_string& row = arr.row(i);
// Aggiungo il nome corrente alla lista dei files da compattare
cmd << ' ' << row.get(0);
if (cmd.len() > 80) // Se la riga ha raggiunto la dimensione giusta...
{
zip_file(archivio, cmd); // ... allora compatto
cmd.cut(0); // e svuoto la riga di comando
}
}
if (cmd.len() > 0 && !aborted)
zip_file(archivio, cmd); // Compatto gli eventuali ultimi rimasti
msg.cut(0);
msg << "Separazione del file " << archivio << " ...";
pi.set_text(msg);
const long size = get_long(F_DISKSIZE) * 1024;
const int disks = split_file(archivio, size);
// Memorizza il numero dei dischetti nel sommario
ini.set("Dischi", disks, main_module); // Aggiorna install.ini
ini.copy_paragraph(main_module, sommario); // Aggiorna sommario
// Se non specifico un path ho gia' finito
const TFilename path = get(F_DISKPATH);
if (path.blank())
return TRUE;
const char drive = toupper(path[0]);
const bool floppy = (drive == 'A' || drive == 'B') && path[1] == ':';
for (int d = 1; d <= disks && !aborted; d++)
{
if (floppy)
message_box("Inserire il disco %d di %d nell'unita' %c:", d, disks, drive);
// Costruisco il nome del file da copiare su dischetto
TFilename src(archivio);
src.ext("");
src << d;
src.ext("zip");
msg.cut(0);
msg << "Generazione del disco " << d << " di " << disks
<< " del modulo " << main_module << " ...";
pi.set_text(msg);
do_events();
bool ok = TRUE;
if (d == 1)
ok = move_file(sommario, path);
if (ok)
ok = move_file(src, path);
aborted = !ok || pi.iscancelled();
}
return TRUE;
}
TFascicolator_mask::TFascicolator_mask()
: TMask("ba1600a")
{
TSheet_field& s = sfield(F_SHEET);
TMask& m = s.sheet_mask();
m.set_handler(S_LIST, list_handler);
m.set_handler(S_SAVE, save_handler);
m.set_handler(S_SAVEAGG, save_handler);
}
///////////////////////////////////////////////////////////
// Programma principale
///////////////////////////////////////////////////////////
class TFascicolator : public TSkeleton_application
{
protected:
virtual bool use_files() const { return FALSE; }
virtual void main_loop();
};
void TFascicolator::main_loop()
{
TFascicolator_mask m;
m.load();
if (m.run() == K_ENTER)
m.save();
}
int ba1600(int argc, char* argv[])
{
TFascicolator app;
app.run(argc, argv, "Megascicolator");
return 0;
}