Welcome!

By registering with us, you'll be able to discuss, share and private message with other members of our community.

SignUp Now!

Declined Data segments in a BTM?

May
12,845
164
Maybe I have missed the boat and there is an elegant way to do this.

I have a list of (17, so far) Windows 10 services that to like to stop. I have done this in a BTM.

Code:
do i=5 to %@lines[%0]
    sc stop %@line[%0,%i]
enddo
quit

service1
service2
...
service17

I can think of several variations on this including a very long "DO /L" command and putting the data into an alternate NTFS stream attached to the BTM but none seem particularly attractive. The method above is kind of minimalist but it causes the BTM to be read many times. How about a mechanism for including data sets in a BTM? Without having given it much thought, perhaps ...

Code:
do i=0 to 16
    sc stop services[%i]
enddo
quit
_DATASEG services
service1
service2
...
service17
_ENDDATASEG services

Data segments could be at the end of a BTM, read only once, and (maybe) put into temporary arrays, or temporary environment variables.
 
Last edited:
Except for editing the data, an NTFS stream works quite nicely.
Code:
do line in @%0:names
    sc stop %line
enddo
quit
 
Far editing NTFS streams just fine.
TextPad, which I use, does also. But you must edit it separately from the BTM.

If you name the stream appropriately (for example with ".txt"), notepad will also edit it ... from TCC ...

Code:
notepad stopsvcs.btm:service_names.txt
 
WinWord.exe and Write.exe will also edit streams. The syntax is as above, and that syntax also works in the Start\Run dialog (full path to the file needed).
 
I've used this kind of idiom on occasion. I won't call it elegant....
Code:
text |! do line in @con: ( echo line = %line )
   This is the first line.
   This is the second line.
   This is not the final line.
   This is.
endtext
 
I've used this kind of idiom on occasion. I won't call it elegant....
Code:
text |! do line in @con: ( echo line = %line )
   This is the first line.
   This is the second line.
   This is not the final line.
   This is.
endtext
Thanks, I like that. Here's a possibly useful modification (for more complicated stuff). With a few GOTOs you could put the "data" at the end and the actual processing up top.
Code:
TEXT | gosub process
number 1
number 2
number 3
ENDTEXT
quit

:process
    do line in @CON
        echo line = %line
    enddo
return
 
I like the DATASEG ... ENDDATASEG idea.

However, I would suggest a variation:

DATASEG services [/a=MyArray]

Or maybe /v=MyArray

If the optional parameter is specified, TCC will automatically load the data into an array variable of that name.

Since TCC supports 4-dimension arrays, it might be helpful to put a data separator.

And possibly allow the user to specify the separator. I personally think being allowed to specify the separator might be a bit of "overkill", but I'll put it out as a possibility to be considered.

In the example, I don't know what "a,b,c,d" would mean/be, since I haven't worked with multi-dimension arrays in TCC and my experience is that each of those would be an integer, thus setting a specific "physical" size for the overall array.

Also, if the array is more than 2 dimensions, how would you indicate that parm3 doesn't go in the second column of the row, it goes in a slot in the "z" dimension? And which column of the dimension?

I'd say limit it to at most a two-dimensional array. I can easily see a command and parameters, for example, but in practice it would be extremely unlikely anyone would try to code a 3- or 4-dimensional array using a DATASEG approach. (Well, at least after the first "Hey, this can't be that hard ..." try!)

DATASEG services [/a=MyArray] [/s=^]

Code:
DATASEG services /a=MyArray[a,b,c,d]
   service1^parm1^parm2^parm3
   service2^parm1^parm2^parm3
   service3^%var1^parm2^parm3
ENDDATASEG
 
I use aliases and gosub here. You can use the same data block over and again.

In essence

alias s 'service %1 stop'
s service
s service2

In some of the command languages that i have written, you can even process tables. eg

command1 %1 %3
command2 %1 %2 %5
etc

Rather like the file list sections on INF files.
 
I use aliases and gosub here. You can use the same data block over and again.

In essence

alias s 'service %1 stop'
s service
s service2
I guess so. But you gave me a good (?) idea ... thanks ... not too cumbersome, straightforward, allows multiple data segments.

Code:
do i=1 to 3
    sc stop %@iniread["%@full[%0]",DATA,%i]
enddo
quit

[DATA]
1=AdobeARMservice
2=PcaSvc
3=SSDPSRV
 
My usual way of dealing with this is to write a rexx script as the processor, and use a ,cmd file as data. The cmd file is an EXTPROC. The idea is based loosely on the old-fashion sprockets used by dot-matrix printers. In essence, the same print file uses sprocket-column 1, 2, 3, 4 to produce differing outputs for different purposes.

I have a number of different processors, such as rxloop, which allows you to construct a table, and select different fields from the data set. The output is then a properly formatted document.

Another EXTPROC batch writes the core of a word document (as an .RTF), and assembles the three parts (header, output, tail) into a word document with letter-head etc. Paragraphs are included on demand.

But using a batch as an INI file sounds like a good go.
 
But using a batch as an INI file sounds like a good go.
Yes, but not if it were speed-critical. It opens and searches the file on every call to @INIREAD. That stuff was already read into memory when the BTM was read into memory. When I originally suggested data segments I imagined that the in-memory copy of the BTM would be searched, much like (I suppose) it is when looking for labels or subroutines. Really fancy would be that TCC "map" the data segments when the BTM is read ... it wouldn't even have to search for them.
 
It probably really depends on how the data might be used. Do you want to run it random-access or in sequence.

If all you mean to do is simplify the typing of commands, and process an array sequentially, then an alias on 'f' might be all you need. Some other letter to keep the data in the batch and not process it.

If you mean to read in various sections of a file and produce code, in the manner of Knuth's 'weave', (which i devised separately in the days of RomBASIC), then you can easily create an array (in REXX), which can be accessed randomly (ie by label commands in the array).

One of the things that i had envisaged with a data segment is to have something in line with a CSV segment.

Something like this

Code:
for $s in :table.csv do
  ren $1.$2 $1.$3
  describe $1.$3 /d"$4"
  end

...
for $s in :table.csv do
  something 
  end

:table.csv
,pkzip,exe,ex_,Pkzip program
,pkunzip,exe,ex_,Pkunzip program

In the csv table, the first character serves as a field separator, eg ;$1;$2;$3;$4;.....
You could use unused fields as 'wing comments'. Because the whole array is in memory, it could be used as an inline table.
These things work a treat. I use a similar affair in my weave proggie. You can check the data directly as a table in the text.
 
Another option;

Code:
@setlocal
@echo off
::
Gosub DATA
::
set MaxItems=%@words[";",%DATA]
set MaxItems=%@dec[%MaxItems]
::
do i=0 to %MaxItems
  echo Item %i=%@word[";",%i,%DATA]
enddo
echo ``
::
::
::
Gosub MOREDATA
::
set MaxItems=%@words[";",%MOREDATA]
set MaxItems=%@dec[%MaxItems]
::
do i=0 to %MaxItems
  echo Item %i=%@word[";",%i,%MOREDATA]
enddo
::
endlocal
quit

:DATA
set DATA=AdobeARMservice;PcaSvc;SSDPSRV
set DATA=%DATA;AarSvc;PrintWorkflowUserSvc;ConsentUxUserSvc
Return

:MOREDATA
set MOREDATA=CaptureService;CDPUserSvc;AdobeARMservice
set MOREDATA=%MOREDATA;ScDeviceEnum;Schedule
Return

Joe
 
I like the DATASEG ... ENDDATASEG idea.

However, I would suggest a variation:

DATASEG services [/a=MyArray]

Or maybe /v=MyArray

If the optional parameter is specified, TCC will automatically load the data into an array variable of that name.

Or make the array automatic with the given name. One-dimensional is fine with me.
Code:
DATA services
SSDPSRV
PcaSvc
ENDDATA
Later, services[0] = SSDPSRV and services[1] = PcaSvc.
 
Or make the array automatic with the given name. One-dimensional is fine with me.
Code:
DATA services
SSDPSRV
PcaSvc
ENDDATA
Later, services[0] = SSDPSRV and services[1] = PcaSvc.

I think you would want the option to have at least two dimensions, e.g.:

VarName, VarVal
or Cmd, Parm

Then array DG would wind up:

DG[0,0] = FirstName
DG[0,1]=John

DG[1,0]=MiddleName
DG[1,1]=Harold
etc.

DATA DG :: Demographic Info
FirstName^John
MiddleName^Harold
Surname^Pearson
GenSfx^II
DOB^11/18/1984
Sex^M
CellPhone^123-456-7890
ENDDATA
 
Thanks, I like that. Here's a possibly useful modification (for more complicated stuff). With a few GOTOs you could put the "data" at the end and the actual processing up top.
Code:
TEXT | gosub process
number 1
number 2
number 3
ENDTEXT
quit

:process
    do line in @CON
        echo line = %line
    enddo
return

Although, as I've mentioned before for something like this I prefer additions to the language rather than custom workarounds, aliases probably could be used here for TEXT | gosub and for a corresponding ENDTEXT, so it would appear:

Code:
DATASEG processname
number 1
number 2
number 3
ENDDATASEG

I don't know how the piping would work if it's part of an alias, since I don't normally use those.
 
Back
Top