The codes will get stored on your hard disk for faster access.
When compiling it the first time, you will need to download also my IDE Tool Helper:
http://www.purebasic.fr/english/viewtop ... 12&t=62033
Next time the HttpInclude inside the code will work (this is a hen egg problem
The tool is self installing into your IDE, so I would recommend not to compile it directly from the IDE, because then it will set the tool to "Purebasic_CompilationX.X".
Better first create an executable and then start this.
And don't forget to add HttpInclude to your custom keywords.
Examples in next thread.
Code: Select all
;*******************************************
;*
;*   Filename:    HTTP_Include.pb
;*   Version:     V1.0.1
;*   Date:        03.05.2021
;*   Author:      HeX0R
;*                http://hex0rs.coderbu.de
;*   URL:         https://www.purebasic.fr/english/viewtopic.php?f=12&t=62689
;*
;*   License:     BEER-WARE
;*                Thomas 'HeX0R' Milz wrote this file. As long as you retain this notice you
;*                can do whatever you want with this stuff. If we meet some day, and you think
;*                this stuff is worth it, you can buy me a beer in return.
;*                                                               HeX0R@coderbu.de
;*
;*   OS:          [x] Windows (> Windows XP!!)
;*                [x] Linux
;*                [?] MacOS (untested)
;*
;*   Description: With this IDE Tool you can
;*                directly include code from the internet
;*
;*
;*   Usage
;*   Just use HTTPInclude "URL" instead of IncludeFile "FILENAME"
;*   e.g.
;*   HTTPInclude "http://www.purebasic.fr/english/viewtopic.php?f=12&t=62033"
;*   you can add also special parameters to the end, e.g.:
;*   HTTPInclude "http://www.purebasic.fr/english/viewtopic.php?f=12&t=62033" ;reload ;raw
;*   Explanation:
;*   ;reload         ->    Will force the source to be reloaded (otherwise it will use the local copy on your PC (if any))
;*   ;raw            ->    Will just use the whole file, otherwise the tool expects the code is part of a forum thread (and will use regular expressions, see ;usesource below)
;*   ;load=#num      ->    load=2 will load the second code it finds in the forum thread
;*   ;usebom=        ->    You can force to read the file with a special BOM, usable: utf8, utf16, ascii
;*   ;usesource=name ->    If you don't set this, the default for the pureboards will be used (or depending on the URL, please see below)
;*                      Create more Regular expressions for different boards, please take a look into %APPDATA%\http_include\settings.prefs:
;*                      [Source_{Name}]
;*                      Name        = Name of the Regex, usually the forum name it will handle.
;*                      URL         = Regex to extract an anchor from the URL
;*                      CodeReg     = Regex to extract the code from the board
;*                      AnchorStart = This is NO Regex! But just a text to find. Anything will start from that position then
;*                      RootURL     = when set, all URLs starting with this string, will be use this Source (if not forced to use a different one via usesource=xxx)
;*                      UseRaw      = when set to 1, all regular expressions will not be used, and the raw data from the URL is directly picked up.
;*
;*
;*******************************************
Enumeration
	#File_Compiled_Source
	#File_Downloaded_Source
	#File_New_Offline_Source
	#File_Error_Log
EndEnumeration
CompilerIf Defined(DEBUG_SOURCE, #PB_Constant) = 0
	;only for debugging purposes
	#DEBUG_SOURCE = "C:\Temp\PB_EditorOutput.pb"
CompilerEndIf
InitNetwork()
EnableExplicit
;On the first run you will need this Include of course (henn/egg problem)!
;Just download it and use IncludeFile instead.
HTTPInclude "https://www.purebasic.fr/english/viewtopic.php?f=12&t=62033"
Structure _Source_
	Name.s
	RootURL.s
	URLStart.s
	URLReg.i
	AnchorStart.s
	CodeReg.i
	UseRaw.b
EndStructure
Global NewList Lines.s()
Global NewList Sources._Source_()
Procedure ErrorLog(Text.s)
	Static First
	If First = 0
		CreateFile(#File_Error_Log, GetUserDirectory(#PB_Directory_ProgramData) + "http_include/error.log")
		First = #True
	EndIf
	If IsFile(#File_Error_Log)
		WriteStringN(#File_Error_Log, FormatDate("%hh:%ii:%ss ", Date()) + Text)
	EndIf
EndProcedure
#REG_1 = "pureboard"
#REG_2 = "#p\d*"
#REG_3 = "(?<=<code>)[^<]*"
#REG_4 = ~"<div id=\"{ANCHOR}\""
Procedure SelectSource(Name.s, RootURL.s)
	Protected Result
	ForEach Sources()
		If Name
			If LCase(Name) = Sources()\Name
				Result = #True
				Break
			EndIf
		ElseIf LCase(RootURL) = Sources()\RootURL
			Result = #True
			Break
		ElseIf Sources()\Name = #REG_1
			Result = #True
			Break
		EndIf
	Next
	ProcedureReturn Result
EndProcedure
Procedure InitSources()
	Protected a$, b$
	If PreferenceGroup("Source_PureBoard") = 0
		WritePreferenceString("RootURL",     "https://www.purebasic.fr/")
		WritePreferenceString("Name",        #REG_1)
		WritePreferenceString("URL",         #REG_2)
		WritePreferenceString("CodeReg",     #REG_3)
		WritePreferenceString("AnchorStart", #REG_4)
		WritePreferenceInteger("UseRaw",     0)
	EndIf
	With Sources()
		If ExaminePreferenceGroups()
			While NextPreferenceGroup()
				a$ = PreferenceGroupName()
				If Left(LCase(a$), 6) = "source_"
					AddElement(Sources())
					\Name    = LCase(Mid(a$, 8))
					\UseRaw  = ReadPreferenceInteger("UseRaw", 0)
					\RootURL = LCase(ReadPreferenceString("RootURL", "https://www.purebasic.fr/"))
					a$       = ReadPreferenceString("URL", #REG_2)
					If a$
						\URLReg = CreateRegularExpression(#PB_Any, a$)
						If \URLReg = 0
							ErrorLog("There is an error in the URL Regex of '" + \Name + "': " + RegularExpressionError())
						EndIf
					EndIf
					\AnchorStart = ReadPreferenceString("AnchorStart", #REG_4)
					a$           = ReadPreferenceString("CodeReg", #REG_3)
					If a$
						\CodeReg = CreateRegularExpression(#PB_Any, a$, #PB_RegularExpression_DotAll)
						If \CodeReg = 0
							ErrorLog("There is an error in the Code Regex of '" + \Name + "': " + RegularExpressionError())
						EndIf
					EndIf
				EndIf
			Wend
		EndIf
		If SelectSource("", "") = 0
			AddElement(Sources())
			\Name        = "pureboard"
			\URLReg      = CreateRegularExpression(#PB_Any, #REG_2)
			\AnchorStart = #REG_4
			\CodeReg     = CreateRegularExpression(#PB_Any, #REG_3, #PB_RegularExpression_DotAll)
			\RootURL     = "https://www.purebasic.fr/"
			\UseRaw      = 0
		EndIf
	EndWith
EndProcedure
Procedure main()
	Protected SourceCode.s, BOM, URL.s, i, j, k, Pos, Reload, PathToPrefs.s, PathToIncludes.s
	Protected a$, Code.s, Changed, FileName.s, Num, Raw, SourceBOM, SourceBOMText.s, Anchor.s, Name.s
	CompilerIf #PB_Compiler_Debugger
	SourceCode = #DEBUG_SOURCE
	CompilerElse
	SourceCode = ProgramParameter(0)
	CompilerEndIf
	;First create our directorys
	PathToPrefs = GetUserDirectory(#PB_Directory_ProgramData) + "http_include/"
	If FileSize(PathToPrefs) <> -2
		CreateDirectory(PathToPrefs)
	EndIf
	;then open (or create) preferences
	If OpenPreferences(PathToPrefs + "settings.prefs") = 0
		CreatePreferences(PathToPrefs + "settings.prefs")
	EndIf
	Debug SourceCode
	InitSources()
	PreferenceGroup("main")
	;this is the path, were the includes will be stored
	PathToIncludes = ReadPreferenceString("PathToIncludes", PathToPrefs + "includes/")
	If SourceCode
		;we have a program parameter
		;let's go
		;first open the SourceCode
		If OpenFile(#File_Compiled_Source, SourceCode)
			BOM       = ReadStringFormat(#File_Compiled_Source)   ;<- save the BOM
			Changed   = #False                ;<- If we changed something, this will be true
			While Eof(#File_Compiled_Source) = 0
				;read any line and add it to our list
				AddElement(Lines())
				Lines() = ReadString(#File_Compiled_Source, BOM)
				If FindString(Trim(Trim(Lines()), #TAB$), "httpinclude", 1, #PB_String_NoCase) = 1 And CountString(Lines(), #DQUOTE$) > 1  ;<- is there a httpinclude at the beginning?
					Code      = ""
					Num       = 1
					SourceBOM = #PB_UTF8                                                   ;<- this is the BOM for the external file
					URL       = StringField(Lines(), 2, #DQUOTE$)                          ;<- get the URL of the include
					Pos       = Len(URL) + 13                                              ;<- start searching position for optional parameters (URL + 2x DQOUTE + httpinclude)
					Reload    = FindString(Lines(), ";reload",  Pos, #PB_String_NoCase)    ;<- if there is a ;reload behind it, this include will be updated
					Raw       = FindString(Lines(), ";raw",     Pos, #PB_String_NoCase)    ;<- if ;raw is an optional parameter we expect a raw code file instead of code inside a forum thread
					i         = FindString(Lines(), ";usesource=", Pos, #PB_String_NoCase)
					If i
						Name = Trim(LCase(Mid(Lines(), i + 11)))
						If SelectSource(Name, "") = 0 And SelectSource("", URL) = 0
							SelectSource("", "")
						EndIf
					ElseIf SelectSource("", URL) = 0
						SelectSource("", "")
					EndIf
					If Raw = 0
						Raw = Sources()\UseRaw
					EndIf
					i = FindString(Lines(), ";load=",   Pos, #PB_String_NoCase) ;<- with load=2 e.g. we load the second code in a thread (only useful for code inside a forum thread)
					If i
						Num = Val(Mid(Lines(), i + 6))
					EndIf
					i = FindString(Lines(), ";usebom=", Pos, #PB_String_NoCase) ;<- by default we expect the external file in UTF8 format, but maybe the site stores it different?
					If i
						SourceBOMText = Mid(Lines(), i + 8)
						If Left(LCase(SourceBOMText), 4) = "utf8"
							SourceBOM = #PB_UTF8
						ElseIf Left(LCase(SourceBOMText), 5) = "utf16"
							SourceBOM = #PB_UTF16
						ElseIf Left(LCase(SourceBOMText), 5) = "ascii"
							SourceBOM = #PB_Ascii
						EndIf
					EndIf
					If PreferenceGroup(URL) And ReadPreferenceString("file_" + Str(Num), "") And Reload = 0            ;<- check if we already have stored this include and there is no ;reload
						Lines()  = "XIncludeFile " + #DQUOTE$ + ReadPreferenceString("file_" + Str(Num), "") + #DQUOTE$  ;<- yes, o.k. just change this line and include our previously loaded (and stored) source
						Changed  = #True                                                            ;<- we changed something
					Else
						;no old include there, or user wants to update it
						;first load the include from the internet to a temporary directory
						If ReceiveHTTPFile(URL, GetTemporaryDirectory() + "http_include.tmp")
							;o.k., now open the html-file
							If ReadFile(#File_Downloaded_Source, GetTemporaryDirectory() + "http_include.tmp") = 0
								ErrorLog("Can't open downloaded file '" + GetTemporaryDirectory() + "http_include.tmp'")
							Else
								i = ReadStringFormat(#File_Downloaded_Source)
								If i <> #PB_Ascii ;if there is a BOM inside the file we overwrite the user setting
									SourceBOM = i
								EndIf
								a$ = ReadString(#File_Downloaded_Source, SourceBOM | #PB_File_IgnoreEOL) ;<- read anything in a$
								CloseFile(#File_Downloaded_Source)                                       ;<- we are finished with the tmp file, we have anything inside a$, so close it and delete it.
								DeleteFile(GetTemporaryDirectory() + "http_include.tmp")
								;now find the start of the code
								If Raw
									;we want to use the whole file as is, not much to do here
									Code = a$
								Else
									;o.k. I guess this code is inside a forum thread, so we need to find the code in it.
									;the below will only work inside pureboards, we probably have to change something for other boards.
									Dim Result$(0)
									If IsRegularExpression(Sources()\URLReg)
										k = ExtractRegularExpression(Sources()\URLReg, URL, Result$())
										If k
											Anchor = Result$(0)
											If Left(Anchor, 1) = "#"
												Anchor = Mid(Anchor, 2)
											EndIf
										EndIf
									EndIf
									If Anchor
										k = FindString(a$, ReplaceString(Sources()\AnchorStart, "{ANCHOR}", Anchor, #PB_String_NoCase), 1, #PB_String_NoCase)
										If k
											a$ = Mid(a$, k)
										EndIf
									EndIf
									If IsRegularExpression(Sources()\CodeReg)
										k = ExtractRegularExpression(Sources()\CodeReg, a$, Result$())
										If k > 0 And Num <= k
											Code = Result$(Num - 1)
											;now we have to decode a few html tags
											;maybe I didn't catch anything, need to keep an eye on this
											Code = ReplaceString(Code, "  ", " ")
											Code = ReplaceString(ReplaceString(Code, "<br />", #CRLF$), " ", " ")
											Code = ReplaceString(ReplaceString(Code, "[", "["), "]", "]")
											Code = ReplaceString(ReplaceString(Code, """, #DQUOTE$), "<", "<")
											Code = ReplaceString(ReplaceString(Code, ">", ">"), "&", "&")
										EndIf
									EndIf
								EndIf
								If Code
									If FileSize(PathToIncludes) <> -2
										;this seems to be the first file we want to store, so create the directory
										CreateDirectory(PathToIncludes)
									EndIf
									If Reload
										;We already had this file before and user wants it to be updated, so just take the original filename
										FileName = ReadPreferenceString("file_" + Str(Num), "")
									Else
										;search for the next unused filename
										j = 0
										While FileSize(PathToIncludes + RSet(Str(j), 6, "0") + ".pb") <> -1
											j + 1
										Wend
										FileName = PathToIncludes + RSet(Str(j), 6, "0") + ".pb"
									EndIf
									;Save our new include
									If CreateFile(#File_New_Offline_Source, FileName)
										WriteStringFormat(#File_New_Offline_Source, #PB_UTF8) ;<- for PB I usually always use UTF8 as file format
										WriteString(#File_New_Offline_Source, Code, #PB_UTF8)
										CloseFile(#File_New_Offline_Source)
										If Reload = 0
											;only write the FileName into our preference file, if there were no "reload" parameter.
											WritePreferenceString("file_" + Str(Num), FileName)
										EndIf
										;Change the line now finally
										Lines() = "XIncludeFile " + #DQUOTE$ + FileName + #DQUOTE$
										Changed = #True ;<- we changed something
									EndIf
								EndIf
							EndIf
						ElseIf Reload ;<- seems the URL couldn't get accessed, but this is just a reload, we can still use our old file
							FileName = ReadPreferenceString("file_" + Str(Num), "")
							Lines()  = "XIncludeFile " + #DQUOTE$ + FileName + #DQUOTE$
							Changed  = #True ;<- we changed something
						Else
							ErrorLog("Can't reach '" + URL + "'!")
						EndIf
					EndIf
				EndIf
			Wend
			CloseFile(#File_Compiled_Source)
			If Changed
				;something changed, so rewrite the file for the compiler
				DeleteFile(SourceCode)
				If CreateFile(#File_Compiled_Source, SourceCode)
					WriteStringFormat(#File_Compiled_Source, BOM)
					ForEach Lines()
						WriteStringN(#File_Compiled_Source, Lines(), BOM)
					Next
					CloseFile(#File_Compiled_Source)
				EndIf
			EndIf
		Else
		EndIf
		ClosePreferences()
	Else
		;no programparameter, so try to install it
		ClosePreferences()
		;See my IDE tool here: http://www.purebasic.fr/english/viewtopic.php?f=12&t=62033
		If IDETOOL::Install("HTTPIncludeA", #DQUOTE$ + "%COMPILEFILE" + #DQUOTE$, "", IDETOOL::#TRIGGER_BEFORE_COMPILING, IDETOOL::#FLAG_WAIT_FOR_TOOL | IDETOOL::#FLAG_START_HIDDEN, 0, 0, 0, 1)
			If IDETOOL::Install("HTTPIncludeB", #DQUOTE$ + "%COMPILEFILE" + #DQUOTE$, "", IDETOOL::#TRIGGER_BEFORE_EXE_CREATION, IDETOOL::#FLAG_WAIT_FOR_TOOL | IDETOOL::#FLAG_START_HIDDEN, 0, 0, 0, 1)
				OpenPreferences(PathToPrefs + "settings.prefs") ;<- open is enough, because we already created it on top of main()
				PreferenceGroup("main")
				a$ = PathRequester("Select Path where online Includes should be stored", PathToIncludes)
				If a$
					WritePreferenceString("PathToIncludes", a$)
				EndIf
				ClosePreferences()
				MessageRequester("Success!", "Successfully installed tool 'HTTPInclude'!" + #LF$ + "If your IDE is open, please restart it." + #LF$ + #LF$ + "(Remember to add HTTPInclude to your custom keywords!)")
			EndIf
		EndIf
	EndIf
	If IsFile(#File_Error_Log)
		CloseFile(#File_Error_Log)
	EndIf
EndProcedure
main()


