cgraph library generate dot file with html label attributes? - html

I'm using graphviz cgraph library to generate a dot file on macbook.
Here's a simple case in c:
#include "graphviz/cgraph.h"
#include <stdio.h>
int main(void) {
Agraph_t *g = agopen("Graph", Agdirected, NULL);
Agsym_t *s = agattr(g, AGNODE, "shape", "record");
Agnode_t *n = agnode(g, "case", TRUE);
char *l = "<<TABLE><TR><TD>Integer</TD></TR></TABLE>>";
agset(n, "label", agstrdup_html(g, l));
FILE *fp = fopen("test.dot", "w");
agwrite(g, fp);
fclose(fp);
agclose(g);
return 0;
}
Compile with clang test.c -o test.exe -lcgraph, I expect it output dot file contains:
digraph {
node [shape=record];
case [label=<<TABLE><TR><TD>Integer</TD></TR></TABLE>>];
But it gives me:
digraph "Graph" {
node [shape=record];
case;
}
How sould I fix it ?

You need to define the attribute label before you can assign it to a node. From the CGraph documentation included in the Graphviz distribution (p. 11):
Setting attributes is a bit more complex. Before attaching an attribute to a graph component, the code must first set up the default case. This is accomplished by a call to agattr. It takes a graph, an object type (AGRAPH, AGNODE, AGEDGE), and two strings as arguments, and return a representation of the attribute. The first string gives the name of the attribute; the second supplies the default value. The graph must be the root graph.
This is true even for attributes normally defined by Graphviz, since the CGraph library is an independent component. In many use cases (including the ones in the Graphviz documentation), the graph is initialised from a base graph. Reading and parsing the base graph with agread will normally populate the standard attributes, so it may not always be necessary to use agattr. But in this case, you're defining the graph from scratch, so you need to define all of your attributes, even label.
I made a few changes to your code; see the comments below for an explanation.
#include "graphviz/cgraph.h"
#include <stdio.h>
int main(void) {
Agraph_t *g = agopen("Graph", Agdirected, NULL);
Agsym_t *attr_shape = agattr(g, AGNODE, "shape", "record");
/* The following is needed before you can use attribute label */
Agsym_t *attr_label = agattr(g, AGNODE, "label", "");
Agnode_t *n = agnode(g, "case", TRUE);
/* Fixed the label. The outer angle brackets are part of the Graphviz
* syntax, not part of the label's value. (Just like quotes for normal
* labels, as the Graphviz documentation says.)
*/
char *label = "<TABLE><TR><TD>Integer</TD></TR></TABLE>";
/* Changed agset to agxset since we have the attribute's descriptor.
* The agset call would have worked, too, but this is a tad more efficient.
*/
agxset(n, attr_label, agstrdup_html(g, label));
agwrite(g, stdout);
agclose(g);
return 0;
}
This produces:

Related

Putting C++ string in HTML code to show value on webserver

I've set up a webserver running on ESP8266 thats currently hosting 7 sites. The sites is written in plain HTML in each diffrent tab in the arduino ide. I have installed the library Pagebuilder to help with making everything look nice and run.
Except one thing. I have a button connected to my ESP8266 which by the time being imitates a sensor input. basicly when the button is pressed my integer "x" increments with 1. I also managed to make a string that replicates "x" and increments with the same value.
I also have a problem with Printing the IPadresse of the server, but thats not as important as the other.
My plan then was writing the string "score" (which contains x) into the HTML tab where it should be output. this obviously didnt work.
Things I've tried:
Splitting up the HTML code where I want the string to be printed and using client.println("");
This didnt work because the two libraries does not cooperate and WiFiClient does not find Pagebuilders server. (basicly, the client.println does nothing when I used it with Pagebuilder).
Reconstructing the HTML page as a literal really long string, and adding in the String with x like this: "html"+score+"html" and adding it into where the HTML page const char were. (basicly replacing the variable with the text that were in the variable).
This did neighter work because the argument "PageElement" from Pagebuilder does only expect one string, and errors out because theres an additional string inside the HTML string.
I've tried sending it as a post req. but this did not output the value either.
I have run out of Ideas to try.
//root page
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <WiFiClient.h>
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#include <WebServer.h>
#endif
#include "PageBuilder.h"
#include "currentGame.h" //tab 1
#if defined(ARDUINO_ARCH_ESP8266)
ESP8266WebServer Server;
ESP8266WebServer server;
#endif
int sensorPin = 2; // button input
int sensorValue = 0;
int x = 0; // the int x
String score=""; //the string x will be in
PageElement CURRENT_GAME_ELEMENT(htmlPage1);
PageBuilder CURRENT_GAME("/current-game", {CURRENT_GAME_ELEMENT}); // this //only showes on href /current-game
void button() {
sensorValue = analogRead(sensorPin); //read the voltage
score="Team 1: "+String((int)x+1); //"make" x a string
if (sensorValue <= 10) { // check if button is pressed
x++; // increment x
Serial.println(x);
Serial.println(score);
delay(100);
}
}
void setup() {
Serial.begin(115200);
pinMode(2, INPUT);
WiFi.softAP("SSID", "PASS");
delay(100);
CURRENT_GAME.insert(Server);
Server.begin();
}
void loop() {
Server.handleClient();
button();
}
// tab 1
const char htmlPage1[] PROGMEM = R"=====(
/*
alot of HTML, basicly the whole website...
..............................................
*/
<div class="jumbotron">
<div align="center">
<h1 class="display-4"> score </h1> // <--- this is where
//I want to print the
//string:
</div>
</div>
)=====";
what I want to do is getting the value of the string score displayed on the website. If I put "score" directly into the HTML, the word score will be displayed, not the value. I want the value displayed.
Edit:
I have figured out how to make the string(score) be printed in the HTML code, thus, I only have to convert the HTML code string back to a char. explanation is in comment below.
Edit 2: (-------------------------solution-------------------------)
Many thanks for the help I've gotten and sorry for being so ignorant, its just so hard being so close and that thing doesnt work. but anyways, What I did was following Pagebuilders example, and making another element to print in current game..
String test(PageArgument& args) {
return score;
}
const char html[] = "<div class=\"jumbotron\"><div align=\"center\"><h1 class=\"display-4\">{{NAME}}</h1></div></div>";
PageElement FRAMEWORK_PAGE_ELEMENT(htmlPage0);
PageBuilder FRAMEWORK_PAGE("/", {FRAMEWORK_PAGE_ELEMENT});
PageElement body_elem(html, { {"NAME", test} });
PageElement CURRENT_GAME_ELEMENT(htmlPage1);
PageBuilder CURRENT_GAME("/current-game", { CURRENT_GAME_ELEMENT, body_elem});
suprisingly easy when I first understood it.. Thanks again.
You could try building your string first, then converting it to a const char
like this: const char * c = str.c_str();
if you can't use a pointer you could try this:
string s = "yourHTML" + score + "moreHTML";
int n = s.length();
char char_array[n + 1];
strcpy(char_array, s.c_str());
additionally you could try the stringstream standard library
This sort of thing is often done using magic tags in your markup that are detected by the server code before it serves the HTML and filled in by executing some sort of callback or filling in a variable, or whatever.
So with this in mind and hoping for the best, I nipped over to: PageBuilder on github and looked to see if there was something similar here. Good news! In one of the examples:
const char html[] = "hello <b>{{NAME}}</b>, <br>Good {{DAYTIME}}.";
...
PageElement body_elem(html, { {"NAME", AsName}, {"DAYTIME", AsDayTime} });
Where {{NAME}} and {{DAYTIME}} are magic tokens. AsName and AsDayTime are functions to be called when the respective tag is encountered while the page is being served.
EDIT: in response to a request to explain differently, I'm not convinced I can do a better job of explaining the code than the example on the library's own github page, so I'll try a wordy description instead:
When you want to serve a webpage to a client, the code needs to know what you want to serve. In the simplest case, it's a static page: the same every time. You can just write the HTML, stick it in a string an be done.
whole_page = "<html>My fixed content</html>";
webserver.serve(whole_page);
But you want some dynamic element(s). As noted, you can do it in a few ways, such as serving some static HTML, then the dynamic bit, then some more static HTML. It seems you've not had much luck like this, and it's rather clunky anyway.
Or you can pre-build a new string out of the three bits and serve that in one chunk, but that's also pretty clunky.
(Aside: taking big strings and adding them together is likely to be slow and memory intensive, two things you really don't want on a little CPU like the ESP8266).
So instead, you allow 'magic' markers in the HTML, using a marker in place of the dynamic content, and serve that instead.
whole_page = "<html>My dynamic content. Value is {{my_value}}</html>";
webserver.serve(whole_page, ...);
The clever bit is that as the page is being served, the webserver is watching the text go by, and when it sees a magic tag, it stops and asks you to fill in the blank, then carries on as before.
Obviously, there is some processing overhead with watching for tags, and some programming overhead with telling it what tags to watch for and how to ask you for the data it needs.
I got advice from a friend who told me I should make a unique argument where I wanted the string(x) and then using some syntax to replace it. I also took inspiration from you Jelle..
what I did was make a unique argument "VAR_CURRENT_SCORE" put that into the HTML where I want the score output, then convert htmlPage1 from a char to a string, use string.replace() and replace "VAR_CURRENT_SCORE" with the string(x) score. this workes as I can see in the serial monitor output.
This is what I did:
//root page
String HTMLstring(htmlstringPage);
delay(100);
HTMLstring.replace("VAR_CURRENT_SCORE", score);
delay(50);
Serial.println("string:");
Serial.println(HTMLstring);
//tab 1 char htmlstringPage[] PROGMEM = R"=====(
<div class="jumbotron">
<div align="center">
<h1 class="display-4">VAR_CURRENT_SCORE</h1>
</div>
</div>
)=====";
However, I still have a small problem left which is converting the string back to char to post it to the website.
To convert the string back:
request->send_P(200, "text/html", HTMLstring.c_str());

GCC produces unaligned function address on Cortex M3

I just placed a function to a specific address using a section and then I output the address of that function and the result is the chosen section address + 1.
This is what I did:
void __attribute__((section (".my_fct_address"))) Fct_Ptr_Test (void)
{
...
}
and
void (*fct_ptr) (void);
fct_ptr = Fct_Ptr_Test;
printf ("0X%X\r\n", (uint32_t)(fct_ptr));
fct_ptr ();
in ld-file:
.my_fct_address 0x800F000 :
{
KEEP(*(.my_fct_address)) /* keep my variable even if not referenced */
} > FLASH
The above printf statement outputs 0x800F001 and Fct_Ptr_Test is called properly
If I set
fct_ptr = 0x800F000;
the system crashes.
If I set
fct_ptr = 0x800F001;
everything is fine again.
If I don't place Fct_Ptr_Test in its own section , ie let the linker place it anywhere I also get an odd address.
Now I wonder how 0x800F001 can be a proper address on a 32 bit controller (ARM cortex M3) and what is stored in 0x800F000.
Even more strange: map-file always shows the even addresses
Can anybody help?
Thanks
Martin
Linker sets the least-significant bit of Thumb functions to 1 to facilitate interworking (see docs). Perhaps that's your case?

LibXML C++ XPathEval Errors

For starters, I'm seeing two types of problems with my the functionality of the code. I can't seem to find the correct element with the function xmlXPathEvalExpression. In addition, I am receiving errors similar to:
HTML parser error : Unexpected end tag : a
This happens for what appears to be all tags in the page.
For some background, the HTML is fetched by CURL and fed into the parsing function immediately after. For the sake of debugging, the return statements have been replaced with printf.
std::string cleanHTMLDoc(std::string &aDoc, std::string &symbolString) {
std::string ctxtID = "//span[id='" + symbolString + "']";
htmlDocPtr doc = htmlParseDoc((xmlChar*) aDoc.c_str(), NULL);
xmlXPathContextPtr context = xmlXPathNewContext(doc);
xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*) ctxtID.c_str(), context);
if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
xmlXPathFreeObject(result);
xmlXPathFreeContext(context);
xmlFreeDoc(doc);
printf("[ERR] Invalid XPath\n");
return "";
}
else {
int size = result->nodesetval->nodeNr;
for (int i = size - 1; i >= 0; --i) {
printf("[DBG] %s\n", result->nodesetval->nodeTab[i]->name);
}
return "";
}
}
The parameter aDoc contains the HTML of the page, and symbolString contains the id of the item we're looking for; in this case yfs_l84_aapl. I have verified that this is an element on the page in the style span[id='yfs_l84_aapl'] or <span id="yfs_l84_aapl">.
From what I've read, the errors fed out of the HTML Parser are due to a lack of a namespace, but when attempting to use the XHTML namespace, I've received the same error. When instead using htmlParseChunk to write out the DOM tree, I do not receive these errors due to options such as HTML_PARSE_NOERROR. However, the htmlParseDoc does not accept these options.
For the sake of information, I am compiling with Visual Studio 2015 and have successfully compiled and executed programs with this library before. My apologies for the poorly formatted code. I recently switched from writing Java in Eclipse.
Any help would be greatly appreciated!
[Edit]
It's not a pretty answer, but I made what I was looking to do work. Instead of looking through the DOM by my (assumed) incorrect XPath expression, I moved through tag by tag to end up where I needed to be, and hard-coded in the correct entry in the nodeTab attribute of the nodeSet.
The code is as follows:
std::string StockIO::cleanHTMLDoc(std::string htmlInput) {
std::string ctxtID = "/html/body/div/div/div/div/div/div/div/div/span/span";
xmlChar* xpath = (xmlChar*) ctxtID.c_str();
htmlDocPtr doc = htmlParseDoc((xmlChar*) htmlInput.c_str(), NULL);
xmlXPathContextPtr context = xmlXPathNewContext(doc);
xmlXPathObjectPtr result = xmlXPathEvalExpression(xpath, context);
if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
xmlXPathFreeObject(result);
xmlXPathFreeContext(context);
xmlFreeDoc(doc);
printf("[ERR] Invalid XPath\n");
return "";
}
else {
xmlNodeSetPtr nodeSet = result->nodesetval;
xmlNodePtr nodePtr = nodeSet->nodeTab[1];
return (char*) xmlNodeListGetString(doc, nodePtr->children, 1);
}
}
I will leave this question open in hopes that someone will help elaborate upon what I did wrong in setting up my XPath expression.

How to wait for an IAsyncAction?

In Windows Store Apps, C++(C# is similar though), doing something like
IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
}.wait();
results in an unhandled exception. Usually it's
Microsoft C++ exception: Concurrency::invalid_operation at memory location 0x0531eb58
And I kind of need for that action to finish to get my In App Purchase information before trying to use it.
The weird thing here is that anything else besides IAsyncAction waits just fine. IAsyncOperation and IAsyncOperationWithProgress worked just fine, but this ? Exception and then crash.
To be honest, I have no idea what's the difference between an IAsyncOperation and an IAsyncAction, they seem similar to me.
UPDATE :
By analyzing this page http://msdn.microsoft.com/en-us/library/vstudio/hh750082.aspx you can figure out that IAsyncAction is just an IAsyncOperation without a return type. But, you can then see that most IAsyncAction-s are waitable. The real problem though is that certain Windows functions just want to execute on a particular thread (for some reason). ReloadSimulatorAsync is one such fine example.
Using code like this :
void WaitForAsync( IAsyncAction ^A )
{
while(A->Status == AsyncStatus::Started)
{
std::chrono::milliseconds milis( 1 );
std::this_thread::sleep_for( milis );
}
AsyncStatus S = A->Status;
}
results in an infinite loop. If called upon other functions it actually works. The problem here is why does a task need to be executed on a particular thread if everything is Async ? Instead of Async it should be RunOn(Main/UI)Thread or similar.
SOLVED, see answer;
Calling wait on the concurrency::task after you create it completely defeats the point of having tasks in the first place.
What you have to realize is that in the Windows Runtime, there are many asynchronous operations that cannot (or should not) be run on (or waited for on) the UI thread; you've found one of them, and now you're trying to wait on it. Instead of potentially causing a deadlock, you're getting an exception.
To remedy this, you need to use a continuation. You're most of the way there; you're already defining a continuation function:
IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
}).wait();
// do important things once the simulator has reloaded
important_things();
...but you're not using it. The purpose of the function you pass into then is to be called off the UI thread once the task is complete. So, instead, you should do this:
IAsyncAction^ Action = CurrentAppSimulator::ReloadSimulatorAsync(proxyFile);
create_task( Action ).then([this]()
{
// do important things once the simulator has reloaded
important_things();
});
Your important post-reload code won't run until the task is complete, and it will run on a background thread so it doesn't block or deadlock the UI.
This is the magical fix that gets the job done :
void WaitForAsync( IAsyncAction ^A )
{
while(A->Status == Windows::Foundation::AsyncStatus::Started)
{
CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
}
Windows::Foundation::AsyncStatus S = A->Status;
}
In general you should use the continuations (.then(...)), like Adam's answer says, and not block. But lets say you want to do a wait for some reason (for testing some code?), you can trigger an event from the last continuation (to use C# parlance):
TEST_METHOD(AsyncOnThreadPoolUsingEvent)
{
std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();
int i;
auto workItem = ref new WorkItemHandler(
[_completed, &i](Windows::Foundation::IAsyncAction^ workItem)
{
Windows::Storage::StorageFolder^ _picturesLibrary = Windows::Storage::KnownFolders::PicturesLibrary;
Concurrency::task<Windows::Storage::StorageFile^> _getFileObjectTask(_picturesLibrary->GetFileAsync(L"art.bmp"));
auto _task2 = _getFileObjectTask.then([_completed, &i](Windows::Storage::StorageFile^ file)
{
i = 90210;
_completed->set();
});
});
auto asyncAction = ThreadPool::RunAsync(workItem);
_completed->wait();
int j = i;
}
By the way, for some reason this method causes an exception when after it is over in visual studio tests. I've tested it in an app too though and it worked with no problem. I'm not quite sure what the problem is with the test.
If anybody wants a C++/Wrl example then I have that too.
Update 07/08/2017: As requested here is a C++/Wrl example. I have just run this in a Universal Windows (10) Test project in Visual Studio 2017. The key thing here is the weird part Callback<Implements< RuntimeClassFlags<ClassicCom >, IWorkItemHandler , FtmBase >> , as opposed to just Callback<IWorkItemHandler> . When I had the latter, the program jammmed except for when it was in a .exe project. I found this solution here: https://social.msdn.microsoft.com/Forums/windowsapps/en-US/ef6f84f6-ad4d-44f0-a107-3922d56662e6/thread-pool-task-blocking-ui-thread . See "agile objects" for more information.
#include "pch.h"
#include "CppUnitTest.h"
#include <Windows.Foundation.h>
#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
#include <wrl/event.h>
#include <memory>
#include "concrt.h"
#include <Windows.System.Threading.h>
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace Windows::System::Threading;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::System::Threading;
namespace TestWinRtAsync10
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(AsyncOnThreadPoolUsingEvent10Wrl)
{
HRESULT hr = BasicThreadpoolTestWithAgileCallback();
Assert::AreEqual(hr, S_OK);
}
HRESULT BasicThreadpoolTestWithAgileCallback()
{
std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();
ComPtr<ABI::Windows::System::Threading::IThreadPoolStatics> _threadPool;
HRESULT hr = GetActivationFactory(HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(), &_threadPool);
ComPtr<IAsyncAction> asyncAction;
hr = _threadPool->RunAsync(Callback<Implements<RuntimeClassFlags<ClassicCom>, IWorkItemHandler, FtmBase>>([&_completed](IAsyncAction* asyncAction) -> HRESULT
{
// Prints a message in debug run of this test
std::ostringstream ss;
ss << "Threadpool work item running.\n";
std::string _string = ss.str();
std::wstring stemp = std::wstring(_string.begin(), _string.end());
OutputDebugString(stemp.c_str());
//
_completed->set();
return S_OK;
}).Get(), &asyncAction);
_completed->wait();
return S_OK;
}
};
}
Update 08/08/2017: More example, per the comments.
#include "pch.h"
#include "CppUnitTest.h"
#include <wrl\wrappers\corewrappers.h>
#include <wrl\client.h>
#include <wrl/event.h>
#include <memory>
#include "concrt.h"
#include <Windows.System.Threading.h>
#include <Windows.ApplicationModel.Core.h>
using namespace ABI::Windows::Foundation;
using namespace Microsoft::WRL;
namespace TestWinRtAsync10
{
TEST_CLASS(TestWinRtAsync_WrlAsyncTesting)
{
public:
TEST_METHOD(PackageClassTest)
{
ComPtr<ABI::Windows::ApplicationModel::IPackageStatics> _pPackageStatics;
HRESULT hr = GetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_ApplicationModel_Package).Get(), &_pPackageStatics);
ComPtr<ABI::Windows::ApplicationModel::IPackage> _pIPackage;
hr = _pPackageStatics->get_Current(&_pIPackage);
ComPtr<ABI::Windows::ApplicationModel::IPackage3> _pIPackage3;
hr = _pIPackage->QueryInterface(__uuidof(ABI::Windows::ApplicationModel::IPackage3), &_pIPackage3);
ComPtr<__FIAsyncOperation_1___FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry> _pAsyncOperation;
hr = _pIPackage3->GetAppListEntriesAsync(&_pAsyncOperation);
std::shared_ptr<Concurrency::event> _completed = std::make_shared<Concurrency::event>();
_pAsyncOperation->put_Completed(Microsoft::WRL::Callback<Implements<RuntimeClassFlags<ClassicCom>, ABI::Windows::Foundation::IAsyncOperationCompletedHandler <__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry*>, FtmBase >>
([&_completed](ABI::Windows::Foundation::IAsyncOperation<__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry*>* pHandler, AsyncStatus status)
{
__FIVectorView_1_Windows__CApplicationModel__CCore__CAppListEntry* _pResults = nullptr;
HRESULT hr = pHandler->GetResults(&_pResults);
ComPtr<ABI::Windows::ApplicationModel::Core::IAppListEntry> _pIAppListEntry;
unsigned int _actual;
hr = _pResults->GetMany(0, 1, &_pIAppListEntry, &_actual);
ComPtr<ABI::Windows::ApplicationModel::IAppDisplayInfo> _pDisplayInfo;
hr = _pIAppListEntry->get_DisplayInfo(&_pDisplayInfo);
Microsoft::WRL::Wrappers::HString _HStrDisplayName;
hr = _pDisplayInfo->get_DisplayName(_HStrDisplayName.GetAddressOf());
const wchar_t * _pWchar_displayName = _HStrDisplayName.GetRawBuffer(&_actual);
OutputDebugString(_pWchar_displayName);
_completed->set();
return hr;
}).Get());
_completed->wait();
};
};
}
This outputted:
TestWinRtAsync10
Just in case anyone needs here is solution in C++/WinRT. Say you have function ProcessFeedAsync() that would return IAsyncAction, just need following simple code:
winrt::init_apartment();
auto processOp{ ProcessFeedAsync() };
// do other work while the feed is being printed.
processOp.get(); // no more work to do; call get() so that we see the printout before the application exits.
source

Flash ABC : What does the number part of <file>.as$<number> in a swfdump

If I take a swf, and run it through swfdump
swfdump.exe -abc file.swf > ABC.txt
One the first run I may get some output in ABC.txt like this
ObjectConfig.as$60
And on a subsequent run of the same SWF get a different output
ObjectConfig.as$61
What is the meaning of the number after the $ ?
This is part of the debug metadata that the mxmlc compiler adds to the bytecode when you do a debug compile, debug=true. If you do a normal release compile, this info is omitted.
This metadata stores filenames and line numbers so that you can see the location in your source while debugging. Although I'm not sure on the exact meaning of these particular numbers, they seem to be a unique identifier or index of that file for the debugger, perhaps in case of two classes with the same name.
The best I can see is in the source code for swfdump, it calls swf_GetString. Somewhere in this chain it adds what looks like a debugLine or a scopeDepth to the end of the class name:
char* swf_GetString(TAG*t)
{
int pos = t->pos;
while(t->pos < t->len && swf_GetU8(t));
/* make sure we always have a trailing zero byte */
if(t->pos == t->len) {
if(t->len == t->memsize) {
swf_ResetWriteBits(t);
swf_SetU8(t, 0);
t->len = t->pos;
}
t->data[t->len] = 0;
}
return (char*)&(t->data[pos]);
}